mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-26 23:34:01 +08:00
some
This commit is contained in:
parent
1016b82df0
commit
163835bec9
@ -61,7 +61,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version)
|
||||
include(generate_product_version)
|
||||
|
||||
set(VERSION_MAJOR 3)
|
||||
set(VERSION_MINOR 13)
|
||||
set(VERSION_MINOR 14)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_REVISION 0)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
include_directories(. util engines)
|
||||
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzusuyu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 )
|
||||
set(enginessrc MKXPZ Ryujinx livecaptions Kincaid vita3k rpcs3 yuzu TYPEMOON ENTERGRAM AGES7 mono Godot 5pb lucasystem LightVN V8 pchooks Artemis KiriKiri YOX PPSSPP CMVS Suika2 )
|
||||
set(enginepath "engine64")
|
||||
set(collector "enginecollection64.cpp")
|
||||
else()
|
||||
|
@ -1,29 +1,34 @@
|
||||
#include"5pb.h"
|
||||
#include"mages/mages.h"
|
||||
namespace{
|
||||
//https://vndb.org/v46553
|
||||
//新宿葬命
|
||||
bool _strncat(){
|
||||
#include "5pb.h"
|
||||
#include "mages/mages.h"
|
||||
namespace
|
||||
{
|
||||
// https://vndb.org/v46553
|
||||
// 新宿葬命
|
||||
bool _strncat()
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address=(uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"),"strncat");
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
*data=stack->ARG2;
|
||||
*len=stack->ARG3;
|
||||
*split=stack->ARG1;
|
||||
hp.address = (uintptr_t)GetProcAddress(GetModuleHandleA("ucrtbase.dll"), "strncat");
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
*data = stack->ARG2;
|
||||
*len = stack->ARG3;
|
||||
*split = stack->ARG1;
|
||||
};
|
||||
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
|
||||
auto s=std::string((char*)data,*len);
|
||||
strReplace(s,"%N","\n");
|
||||
//sub_140096E80
|
||||
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
strReplace(s, "%N", "\n");
|
||||
// sub_140096E80
|
||||
//%I %B %C %R( %Z %%
|
||||
return write_string_overwrite(data,len,s);
|
||||
return write_string_overwrite(data, len, s);
|
||||
};
|
||||
return NewHook(hp,"strncat");
|
||||
return NewHook(hp, "strncat");
|
||||
}
|
||||
}
|
||||
bool _5pb::attach_function() {
|
||||
//CHAOS;HEAD_NOAH
|
||||
bool b3=hookmages::MAGES();
|
||||
return b3||_strncat();
|
||||
bool _5pb::attach_function()
|
||||
{
|
||||
// CHAOS;HEAD_NOAH
|
||||
bool b3 = hookmages::MAGES();
|
||||
return b3 || _strncat();
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
|
||||
|
||||
class _5pb:public ENGINE{
|
||||
public:
|
||||
_5pb(){
|
||||
is_engine_certain=false;
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
check_by_target=check_by_list{ L"data\\*.cpk",L"*.cpk"};
|
||||
|
||||
class _5pb : public ENGINE
|
||||
{
|
||||
public:
|
||||
_5pb()
|
||||
{
|
||||
is_engine_certain = false;
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"data\\*.cpk", L"*.cpk"};
|
||||
};
|
||||
bool attach_function();
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,80 +1,97 @@
|
||||
#include"AGES7.h"
|
||||
namespace{
|
||||
//Muv-Luv Alternative - Total Eclipse
|
||||
//https://vndb.org/v7052
|
||||
bool _1(){
|
||||
//HSN65001#-44@234699:te-win64vc14-release.exe
|
||||
BYTE b1[]={
|
||||
0x48,XX2,0xb0,0xfe,0xff,0xff,
|
||||
0x4c,XX2,0xb8,0x01,0x00,0x00,
|
||||
#include "AGES7.h"
|
||||
namespace
|
||||
{
|
||||
// Muv-Luv Alternative - Total Eclipse
|
||||
// https://vndb.org/v7052
|
||||
bool _1()
|
||||
{
|
||||
// HSN65001#-44@234699:te-win64vc14-release.exe
|
||||
BYTE b1[] = {
|
||||
//clang-format off
|
||||
0x48, XX2, 0xb0, 0xfe, 0xff, 0xff,
|
||||
0x4c, XX2, 0xb8, 0x01, 0x00, 0x00,
|
||||
//clang-format on
|
||||
|
||||
};
|
||||
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
|
||||
if(addr==0)return false;
|
||||
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.offset=get_reg(regs::rdi);
|
||||
auto succ=NewHook(hp,"Ages7_1");
|
||||
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){
|
||||
hp.address=addr;
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.offset=get_reg(regs::rbx);
|
||||
succ|=NewHook(hp,"Ages7_3");
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.offset = get_reg(regs::rdi);
|
||||
auto succ = NewHook(hp, "Ages7_1");
|
||||
if (addr = MemDbg::findEnclosingAlignedFunction(addr))
|
||||
{
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.offset = get_reg(regs::rbx);
|
||||
succ |= NewHook(hp, "Ages7_3");
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
bool _2(){
|
||||
//HSN65001#-44@2346AC:te-win64vc14-release.exe
|
||||
BYTE b1[]={
|
||||
0x48,XX2,0x10,
|
||||
0x48,XX2,0xb0,0x01,0x00,0x00,
|
||||
XX2,0xc0,0x08,0x00,0x00
|
||||
bool _2()
|
||||
{
|
||||
// HSN65001#-44@2346AC:te-win64vc14-release.exe
|
||||
BYTE b1[] = {
|
||||
//clang-format off
|
||||
0x48, XX2, 0x10,
|
||||
0x48, XX2, 0xb0, 0x01, 0x00, 0x00,
|
||||
XX2, 0xc0, 0x08, 0x00, 0x00
|
||||
//clang-format on
|
||||
|
||||
};
|
||||
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
|
||||
if(addr==0)return false;
|
||||
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.offset=get_reg(regs::rdi);
|
||||
auto suc=NewHook(hp,"Ages7_2");
|
||||
if(addr=MemDbg::findEnclosingAlignedFunction(addr)){
|
||||
hp.address=addr;
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.offset=get_reg(regs::rbx);
|
||||
suc|=NewHook(hp,"Ages7_3");
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.offset = get_reg(regs::rdi);
|
||||
auto suc = NewHook(hp, "Ages7_2");
|
||||
if (addr = MemDbg::findEnclosingAlignedFunction(addr))
|
||||
{
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.offset = get_reg(regs::rbx);
|
||||
suc |= NewHook(hp, "Ages7_3");
|
||||
}
|
||||
return suc;
|
||||
}
|
||||
bool _3(){
|
||||
//HSN65001#-14@3D9814:te-win64vc14-release.exe
|
||||
BYTE b1[]={
|
||||
0x48,0x8b,0x1b,
|
||||
0x48,0x8b,0x01,
|
||||
0x48,0x8b,0xd3,
|
||||
0xff,0x10,
|
||||
0x48,0x8b,0x45,0xc8,
|
||||
0x48,0x8b,0x4d,0xc0,
|
||||
0x48,0x2b,0xc1,
|
||||
0x48,0xc1,0xf8,0x03,
|
||||
0x48,0x85,0xc0,
|
||||
}
|
||||
bool _3()
|
||||
{
|
||||
// HSN65001#-14@3D9814:te-win64vc14-release.exe
|
||||
BYTE b1[] = {
|
||||
//clang-format off
|
||||
0x48, 0x8b, 0x1b,
|
||||
0x48, 0x8b, 0x01,
|
||||
0x48, 0x8b, 0xd3,
|
||||
0xff, 0x10,
|
||||
0x48, 0x8b, 0x45, 0xc8,
|
||||
0x48, 0x8b, 0x4d, 0xc0,
|
||||
0x48, 0x2b, 0xc1,
|
||||
0x48, 0xc1, 0xf8, 0x03,
|
||||
0x48, 0x85, 0xc0,
|
||||
//clang-format on
|
||||
};
|
||||
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
|
||||
if(addr==0)return false;
|
||||
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address=addr+3;
|
||||
hp.type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp.offset=get_reg(regs::rbx);
|
||||
return NewHook(hp,"Ages7_4");
|
||||
}
|
||||
bool all(){
|
||||
auto _=_1();
|
||||
_=_2()||_;
|
||||
_=_3()||_;
|
||||
hp.address = addr + 3;
|
||||
hp.type = USING_STRING | CODEC_UTF8 | NO_CONTEXT;
|
||||
hp.offset = get_reg(regs::rbx);
|
||||
return NewHook(hp, "Ages7_4");
|
||||
}
|
||||
bool all()
|
||||
{
|
||||
auto _ = _1();
|
||||
_ = _2() || _;
|
||||
_ = _3() || _;
|
||||
return _;
|
||||
}
|
||||
}
|
||||
bool AGES7::attach_function(){
|
||||
bool AGES7::attach_function()
|
||||
{
|
||||
return all();
|
||||
}
|
@ -1,12 +1,13 @@
|
||||
|
||||
|
||||
class AGES7:public ENGINE{
|
||||
public:
|
||||
AGES7(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ALL;
|
||||
check_by_target=check_by_list{L"obb\\pack.bin",L"erc_nospfx.dll"};
|
||||
class AGES7 : public ENGINE
|
||||
{
|
||||
public:
|
||||
AGES7()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ALL;
|
||||
check_by_target = check_by_list{L"obb\\pack.bin", L"erc_nospfx.dll"};
|
||||
};
|
||||
bool attach_function();
|
||||
bool attach_function();
|
||||
};
|
@ -54,8 +54,8 @@ bool Artemis64()
|
||||
|
||||
bool Artemis64x()
|
||||
{
|
||||
//https://vndb.org/v50832
|
||||
//きら☆かの 体验版
|
||||
// https://vndb.org/v50832
|
||||
// きら☆かの 体验版
|
||||
|
||||
/*
|
||||
__int64 __fastcall sub_1401B13F0(__int64 a1, unsigned __int64 a2, char **a3)
|
||||
|
@ -1,11 +1,13 @@
|
||||
|
||||
|
||||
class Artemis:public ENGINE{
|
||||
public:
|
||||
Artemis(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.pfs";
|
||||
class Artemis : public ENGINE
|
||||
{
|
||||
public:
|
||||
Artemis()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"*.pfs";
|
||||
};
|
||||
bool attach_function();
|
||||
bool attach_function();
|
||||
};
|
@ -1,57 +1,68 @@
|
||||
#include"CMVS.h"
|
||||
namespace{
|
||||
bool EMbed(){
|
||||
//有多个,但是只有最后一个是有效的
|
||||
const uint8_t bytes[] = {
|
||||
0xB8,0x42,0x81,0x00,0x00,
|
||||
0x66,XX2,0x74,XX,
|
||||
0xB8,0x76,0x81,0x00,0x00,
|
||||
0x66,XX2,0x74,XX,
|
||||
0xB8,0x78,0x81,0x00,0x00,
|
||||
0x66,XX2,0x74,XX,
|
||||
};
|
||||
bool res=false;
|
||||
auto addr=processStartAddress;
|
||||
|
||||
std::vector<uintptr_t>already;
|
||||
|
||||
while(addr){
|
||||
addr = MemDbg::findBytes(bytes,sizeof(bytes),addr+1,processStopAddress);
|
||||
if(addr==0)continue;
|
||||
#include "CMVS.h"
|
||||
namespace
|
||||
{
|
||||
bool EMbed()
|
||||
{
|
||||
// 有多个,但是只有最后一个是有效的
|
||||
const uint8_t bytes[] = {
|
||||
//clang-format off
|
||||
0xB8, 0x42, 0x81, 0x00, 0x00,
|
||||
0x66, XX2, 0x74, XX,
|
||||
0xB8, 0x76, 0x81, 0x00, 0x00,
|
||||
0x66, XX2, 0x74, XX,
|
||||
0xB8, 0x78, 0x81, 0x00, 0x00,
|
||||
0x66, XX2, 0x74, XX,
|
||||
//clang-format on
|
||||
};
|
||||
bool res = false;
|
||||
auto addr = processStartAddress;
|
||||
|
||||
std::vector<uintptr_t> already;
|
||||
|
||||
while (addr)
|
||||
{
|
||||
addr = MemDbg::findBytes(bytes, sizeof(bytes), addr + 1, processStopAddress);
|
||||
if (addr == 0)
|
||||
continue;
|
||||
auto f = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
if(f==0)continue;
|
||||
if(std::find(already.begin(),already.end(),f)!=already.end())continue;
|
||||
if (f == 0)
|
||||
continue;
|
||||
if (std::find(already.begin(), already.end(), f) != already.end())
|
||||
continue;
|
||||
already.push_back(f);
|
||||
|
||||
}
|
||||
if (already.size())
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = already.back();
|
||||
hp.offset = get_reg(regs::rdx);
|
||||
|
||||
hp.type = EMBED_ABLE | USING_STRING | EMBED_BEFORE_SIMPLE | EMBED_AFTER_NEW | EMBED_DYNA_SJIS;
|
||||
hp.hook_font = F_GetGlyphOutlineA;
|
||||
res |= NewHook(hp, "EmbedCMVS");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
if(already.size()){
|
||||
|
||||
bool CMVSh()
|
||||
{
|
||||
|
||||
DWORD align = 0xCCCCCCCC;
|
||||
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
|
||||
if (!addr)
|
||||
return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = already.back() ;
|
||||
hp.offset=get_reg(regs::rdx);
|
||||
|
||||
hp.type=EMBED_ABLE|USING_STRING|EMBED_BEFORE_SIMPLE|EMBED_AFTER_NEW|EMBED_DYNA_SJIS;
|
||||
hp.hook_font=F_GetGlyphOutlineA;
|
||||
res|=NewHook(hp, "EmbedCMVS");
|
||||
hp.address = addr + 4;
|
||||
hp.offset = get_reg(regs::r8);
|
||||
hp.type = CODEC_ANSI_BE;
|
||||
|
||||
return NewHook(hp, "CMVS");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool CMVSh() {
|
||||
|
||||
DWORD align = 0xCCCCCCCC;
|
||||
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
|
||||
if (!addr) return false;
|
||||
|
||||
HookParam hp;
|
||||
hp.address = addr+4;
|
||||
hp.offset=get_reg(regs::r8);
|
||||
hp.type = CODEC_ANSI_BE;
|
||||
|
||||
return NewHook(hp, "CMVS");
|
||||
}
|
||||
}
|
||||
bool CMVS::attach_function(){
|
||||
bool b1=CMVSh();
|
||||
bool b2=EMbed();
|
||||
return b1||b2;
|
||||
bool CMVS::attach_function()
|
||||
{
|
||||
bool b1 = CMVSh();
|
||||
bool b2 = EMbed();
|
||||
return b1 || b2;
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
|
||||
|
||||
class CMVS:public ENGINE{
|
||||
public:
|
||||
CMVS(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"data\\pack\\*.cpz";
|
||||
class CMVS : public ENGINE
|
||||
{
|
||||
public:
|
||||
CMVS()
|
||||
{
|
||||
|
||||
|
||||
// jichi 8/19/2013: DO NOT WORK for games like「ハピメア」
|
||||
//if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
|
||||
// InsertCMVSHook();
|
||||
// return true;
|
||||
//}
|
||||
};
|
||||
bool attach_function();
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"data\\pack\\*.cpz";
|
||||
|
||||
// jichi 8/19/2013: DO NOT WORK for games like「ハピメア」
|
||||
// if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
|
||||
// InsertCMVSHook();
|
||||
// return true;
|
||||
//}
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
@ -1,26 +1,29 @@
|
||||
#include"Godot.h"
|
||||
#include "Godot.h"
|
||||
|
||||
bool InsertGodotHook_X64() {
|
||||
const BYTE bytes[] = { 0x8B,0x40,0xFC,0x83,0xF8,0x01,0x83,0xD0,0xFF,0x41,0x39,0xC6 };
|
||||
bool InsertGodotHook_X64()
|
||||
{
|
||||
const BYTE bytes[] = {0x8B, 0x40, 0xFC, 0x83, 0xF8, 0x01, 0x83, 0xD0, 0xFF, 0x41, 0x39, 0xC6};
|
||||
|
||||
ULONG64 range = min(processStopAddress - processStartAddress, MAX_REL_ADDR);
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) {
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
|
||||
{
|
||||
HookParam myhp;
|
||||
myhp.address = addr;
|
||||
|
||||
myhp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT; // /HQ 不使用上下文区分 把所有线程的文本都提取
|
||||
//myhp.padding = 0xc;//[esp+4]+padding
|
||||
// data_offset
|
||||
myhp.offset=get_reg(regs::rax);
|
||||
myhp.text_fun = [](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* count)
|
||||
// myhp.padding = 0xc;//[esp+4]+padding
|
||||
// data_offset
|
||||
myhp.offset = get_reg(regs::rax);
|
||||
myhp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *count)
|
||||
{
|
||||
*data=(stack->rax);
|
||||
int len = *(int*)(*data - 4);
|
||||
if(len!=wcslen((wchar_t*)*data))return;
|
||||
*count=len*2;
|
||||
*data = (stack->rax);
|
||||
int len = *(int *)(*data - 4);
|
||||
if (len != wcslen((wchar_t *)*data))
|
||||
return;
|
||||
*count = len * 2;
|
||||
};
|
||||
char nameForUser[HOOK_NAME_SIZE] = "RichTextLabel_add_text";
|
||||
|
||||
|
||||
ConsoleOutput("Insert: Godot_add_text_X64 Hook ");
|
||||
return NewHook(myhp, nameForUser);
|
||||
}
|
||||
@ -28,27 +31,29 @@ bool InsertGodotHook_X64() {
|
||||
ConsoleOutput("Godot_x64: pattern not found");
|
||||
return false;
|
||||
}
|
||||
bool InsertGodotHook2_X64() {
|
||||
|
||||
bool InsertGodotHook2_X64()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* https://vndb.org/r109138
|
||||
*/
|
||||
* Sample games:
|
||||
* https://vndb.org/r109138
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here
|
||||
0x4C, 0x89, 0xE1, // mov rcx,r12
|
||||
0xE8, XX4, // call NULL-Windows.exe+D150
|
||||
0x49, 0x8B, 0x06, // mov rax,[r14]
|
||||
0x48, 0x85, 0xC0, // test rax,rax
|
||||
0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4
|
||||
0x48, 0x8B, 0x94, 0x24, XX4, // mov rdx,[rsp+000001C0] <- hook here
|
||||
0x4C, 0x89, 0xE1, // mov rcx,r12
|
||||
0xE8, XX4, // call NULL-Windows.exe+D150
|
||||
0x49, 0x8B, 0x06, // mov rax,[r14]
|
||||
0x48, 0x85, 0xC0, // test rax,rax
|
||||
0x0F, 0x85, XX4 // jne NULL-Windows.exe+A359D4
|
||||
|
||||
};
|
||||
|
||||
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) {
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.offset=get_reg(regs::rcx);
|
||||
hp.offset = get_reg(regs::rcx);
|
||||
hp.type = USING_STRING | CODEC_UTF16;
|
||||
ConsoleOutput("INSERT Godot2_x64 Hook ");
|
||||
return NewHook(hp, "Godot2_x64");
|
||||
@ -57,8 +62,9 @@ bool InsertGodotHook2_X64() {
|
||||
ConsoleOutput("Godot2_x64: pattern not found");
|
||||
return false;
|
||||
}
|
||||
bool Godot::attach_function(){
|
||||
auto _= InsertGodotHook_X64();
|
||||
_=InsertGodotHook2_X64()||_;
|
||||
bool Godot::attach_function()
|
||||
{
|
||||
auto _ = InsertGodotHook_X64();
|
||||
_ = InsertGodotHook2_X64() || _;
|
||||
return _;
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
|
||||
|
||||
class Godot:public ENGINE{
|
||||
public:
|
||||
Godot(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
check_by_target=L"*.pck";
|
||||
};
|
||||
bool attach_function();
|
||||
class Godot : public ENGINE
|
||||
{
|
||||
public:
|
||||
Godot()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
check_by_target = L"*.pck";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,38 +1,42 @@
|
||||
#include"Kincaid.h"
|
||||
namespace{
|
||||
bool _1(){
|
||||
// .text:0000000140230D80 mov rsi, rax
|
||||
// .text:0000000140230D83 mov edx, 1
|
||||
// .text:0000000140230D88 mov rcx, rdi
|
||||
// .text:0000000140230D8B call sub_1402B35B0
|
||||
// .text:0000000140230D90 lea ebx, [rax-1]
|
||||
// .text:0000000140230D93 mov edx, 2
|
||||
// .text:0000000140230D98 mov rcx, rdi
|
||||
// .text:0000000140230D9B call sub_1402B35B0
|
||||
BYTE b1[]={
|
||||
0x48,0x8b,0xf0,
|
||||
0xba,0x01,0x00,0x00,0x00,
|
||||
0x48,0x8b,0xcf,
|
||||
0xe8,XX4,
|
||||
0x8d,0x58,0xff,
|
||||
0xba,0x02,0x00,0x00,0x00,
|
||||
0x48,0x8b,0xcf,
|
||||
0xe8,XX4
|
||||
};
|
||||
auto addr=MemDbg::findBytes(b1,sizeof(b1),processStartAddress,processStopAddress);
|
||||
if(addr==0)return false;
|
||||
#include "Kincaid.h"
|
||||
namespace
|
||||
{
|
||||
bool _1()
|
||||
{
|
||||
// .text:0000000140230D80 mov rsi, rax
|
||||
// .text:0000000140230D83 mov edx, 1
|
||||
// .text:0000000140230D88 mov rcx, rdi
|
||||
// .text:0000000140230D8B call sub_1402B35B0
|
||||
// .text:0000000140230D90 lea ebx, [rax-1]
|
||||
// .text:0000000140230D93 mov edx, 2
|
||||
// .text:0000000140230D98 mov rcx, rdi
|
||||
// .text:0000000140230D9B call sub_1402B35B0
|
||||
BYTE b1[] = {
|
||||
0x48, 0x8b, 0xf0,
|
||||
0xba, 0x01, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8b, 0xcf,
|
||||
0xe8, XX4,
|
||||
0x8d, 0x58, 0xff,
|
||||
0xba, 0x02, 0x00, 0x00, 0x00,
|
||||
0x48, 0x8b, 0xcf,
|
||||
0xe8, XX4};
|
||||
auto addr = MemDbg::findBytes(b1, sizeof(b1), processStartAddress, processStopAddress);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.type=USING_STRING|CODEC_UTF8;
|
||||
hp.offset=get_reg(regs::rax);
|
||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
*data=stack->rax;
|
||||
if(stack->retaddr==(DWORD)-1)
|
||||
*len=strlen((char*)*data);
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING | CODEC_UTF8;
|
||||
hp.offset = get_reg(regs::rax);
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
*data = stack->rax;
|
||||
if (stack->retaddr == (DWORD)-1)
|
||||
*len = strlen((char *)*data);
|
||||
};
|
||||
return NewHook(hp,"Kincaid");
|
||||
return NewHook(hp, "Kincaid");
|
||||
}
|
||||
}
|
||||
bool Kincaid::attach_function(){
|
||||
bool Kincaid::attach_function()
|
||||
{
|
||||
return _1();
|
||||
}
|
@ -26,15 +26,17 @@
|
||||
// }
|
||||
// }
|
||||
|
||||
class Kincaid:public ENGINE{
|
||||
public:
|
||||
Kincaid(){
|
||||
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
check_by_target=[](){
|
||||
return Util::SearchResourceString(L"Cookiedraggy")|| Util::SearchResourceString(L"The Adventures of Kincaid");
|
||||
};
|
||||
class Kincaid : public ENGINE
|
||||
{
|
||||
public:
|
||||
Kincaid()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid");
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
@ -1,68 +1,70 @@
|
||||
#include"KiriKiri.h"
|
||||
#include "KiriKiri.h"
|
||||
bool InsertKiriKiriZHook()
|
||||
{
|
||||
|
||||
/*
|
||||
* Sample games:
|
||||
* RJ351843
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here
|
||||
0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx
|
||||
0x53, // push rbx
|
||||
0x56, // push rsi
|
||||
0x57, // push rdi
|
||||
0x41, 0x54, // push r12
|
||||
0x41, 0x55, // push r13
|
||||
0x41, 0x56, // push r14
|
||||
0x41, 0x57, // push r15
|
||||
0x48, 0x83, 0xEC, 0x40, // sub rsp,40
|
||||
0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE
|
||||
};
|
||||
{
|
||||
|
||||
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range)) {
|
||||
HookParam hp;
|
||||
hp.address = addr + 1;
|
||||
hp.offset=get_reg(regs::rcx);
|
||||
hp.index = 0x18;
|
||||
hp.type = CODEC_UTF16 | DATA_INDIRECT;
|
||||
return NewHook(hp, "KiriKiriZ");
|
||||
}
|
||||
return false;
|
||||
/*
|
||||
* Sample games:
|
||||
* RJ351843
|
||||
*/
|
||||
const BYTE bytes[] = {
|
||||
0xCC, // int 3
|
||||
0x4C, 0x89, 0x44, 0x24, 0x18, // mov [rsp+18],r8 <- hook here
|
||||
0x48, 0x89, 0x54, 0x24, 0x10, // mov [rsp+10],rdx
|
||||
0x53, // push rbx
|
||||
0x56, // push rsi
|
||||
0x57, // push rdi
|
||||
0x41, 0x54, // push r12
|
||||
0x41, 0x55, // push r13
|
||||
0x41, 0x56, // push r14
|
||||
0x41, 0x57, // push r15
|
||||
0x48, 0x83, 0xEC, 0x40, // sub rsp,40
|
||||
0x48, 0xC7, 0x44, 0x24, 0x30, 0xFE, 0xFF, 0xFF, 0xFF // mov qword ptr [rsp+30],FFFFFFFFFFFFFFFE
|
||||
};
|
||||
|
||||
ULONG64 range = min(processStopAddress - processStartAddress, X64_MAX_REL_ADDR);
|
||||
for (auto addr : Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, processStartAddress, processStartAddress + range))
|
||||
{
|
||||
HookParam hp;
|
||||
hp.address = addr + 1;
|
||||
hp.offset = get_reg(regs::rcx);
|
||||
hp.index = 0x18;
|
||||
hp.type = CODEC_UTF16 | DATA_INDIRECT;
|
||||
return NewHook(hp, "KiriKiriZ");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Insertkrkrz64Hook()
|
||||
{
|
||||
const BYTE BYTES[] = {
|
||||
0x41,0x0F,0xB7,0x44,0x24,0x04,
|
||||
0x89,0x43,0x20,
|
||||
0x41,0x0F,0xB7,0x44,0x24,0x06,
|
||||
0x89,0x43,0x24,
|
||||
0x41,0x0F,0xBF,0x44,0x24,0x0C,
|
||||
0x89,0x43,0x14
|
||||
};
|
||||
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
|
||||
for (auto addr : addrs) {
|
||||
ConsoleOutput("krkrz64 %p", addr);
|
||||
const BYTE funcstart[] = { 0xcc,0xcc,0xcc,0xcc };
|
||||
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
|
||||
if (addr == 0)continue;
|
||||
addr += 4;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF16| DATA_INDIRECT;
|
||||
hp.offset=get_reg(regs::rcx);
|
||||
hp.index = 0x18;
|
||||
ConsoleOutput("krkrz64 %p %x", addr);
|
||||
return NewHook(hp, "krkrz64");
|
||||
}
|
||||
const BYTE BYTES[] = {
|
||||
0x41, 0x0F, 0xB7, 0x44, 0x24, 0x04,
|
||||
0x89, 0x43, 0x20,
|
||||
0x41, 0x0F, 0xB7, 0x44, 0x24, 0x06,
|
||||
0x89, 0x43, 0x24,
|
||||
0x41, 0x0F, 0xBF, 0x44, 0x24, 0x0C,
|
||||
0x89, 0x43, 0x14};
|
||||
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
ConsoleOutput("krkrz64 %p", addr);
|
||||
const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc};
|
||||
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
|
||||
if (addr == 0)
|
||||
continue;
|
||||
addr += 4;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF16 | DATA_INDIRECT;
|
||||
hp.offset = get_reg(regs::rcx);
|
||||
hp.index = 0x18;
|
||||
ConsoleOutput("krkrz64 %p %x", addr);
|
||||
return NewHook(hp, "krkrz64");
|
||||
}
|
||||
|
||||
ConsoleOutput("krkrz64 failed");
|
||||
return false;
|
||||
ConsoleOutput("krkrz64 failed");
|
||||
return false;
|
||||
}
|
||||
bool KiriKiri::attach_function()
|
||||
{
|
||||
return Insertkrkrz64Hook() || InsertKiriKiriZHook();
|
||||
}
|
||||
bool KiriKiri::attach_function() {
|
||||
return Insertkrkrz64Hook()||InsertKiriKiriZHook();
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
|
||||
|
||||
class KiriKiri:public ENGINE{
|
||||
public:
|
||||
KiriKiri(){
|
||||
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
is_engine_certain=false;
|
||||
check_by_target=[](){
|
||||
return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)");
|
||||
class KiriKiri : public ENGINE
|
||||
{
|
||||
public:
|
||||
KiriKiri()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
is_engine_certain = false;
|
||||
check_by_target = []()
|
||||
{
|
||||
return Util::CheckFile(L"*.xp3") || Util::SearchResourceString(L"TVP(KIRIKIRI)");
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class LightVN:public ENGINE{
|
||||
public:
|
||||
LightVN(){
|
||||
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
is_engine_certain=false;
|
||||
check_by_target=check_by_list{L"Data/Scripts/title.txt",L"Data/data*.vndat",L"Scripts/000_title.txt"};
|
||||
};
|
||||
bool attach_function();
|
||||
class LightVN : public ENGINE
|
||||
{
|
||||
public:
|
||||
LightVN()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
is_engine_certain = false;
|
||||
check_by_target = check_by_list{L"Data/Scripts/title.txt", L"Data/data*.vndat", L"Scripts/000_title.txt"};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include"PPSSPP.h"
|
||||
#include"ppsspp/psputils.hpp"
|
||||
#include "PPSSPP.h"
|
||||
#include "ppsspp/psputils.hpp"
|
||||
|
||||
bool PPSSPPengine::attach_function()
|
||||
{
|
||||
|
@ -1,12 +1,14 @@
|
||||
|
||||
|
||||
class PPSSPPengine:public ENGINE{
|
||||
public:
|
||||
PPSSPPengine(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"PPSSPP*.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
class PPSSPPengine : public ENGINE
|
||||
{
|
||||
public:
|
||||
PPSSPPengine()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"PPSSPP*.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -44,6 +44,8 @@ namespace
|
||||
}
|
||||
bool Ryujinx::attach_function()
|
||||
{
|
||||
WarningOutput("not support ryuujinx, please use yuzu/sudachi instead.");
|
||||
return true;
|
||||
auto invokeCompileMethodHelper = processStartAddress + 0x84CC0;
|
||||
getMethodNameFromMetadata = (decltype(getMethodNameFromMetadata))(processStartAddress + 0x7AED0);
|
||||
HookParam hp;
|
||||
|
@ -1,18 +1,21 @@
|
||||
#include"Suika2.h"
|
||||
|
||||
bool Suika2_msvcrt() {
|
||||
auto msvcrt=GetModuleHandle(L"msvcrt.dll");
|
||||
if(msvcrt==0)return 0;
|
||||
auto _strdup=GetProcAddress(msvcrt,"_strdup");
|
||||
if(_strdup==0)return 0;
|
||||
#include "Suika2.h"
|
||||
|
||||
bool Suika2_msvcrt()
|
||||
{
|
||||
auto msvcrt = GetModuleHandle(L"msvcrt.dll");
|
||||
if (msvcrt == 0)
|
||||
return 0;
|
||||
auto _strdup = GetProcAddress(msvcrt, "_strdup");
|
||||
if (_strdup == 0)
|
||||
return 0;
|
||||
HookParam hp;
|
||||
hp.address=(uintptr_t)_strdup;
|
||||
hp.type=USING_STRING|CODEC_UTF8;
|
||||
hp.offset=get_reg(regs::rcx);
|
||||
return NewHook(hp,"Suika2_msvcrt");
|
||||
|
||||
}
|
||||
bool Suika2::attach_function() {
|
||||
auto _1=Suika2_msvcrt();
|
||||
return _1 ;
|
||||
hp.address = (uintptr_t)_strdup;
|
||||
hp.type = USING_STRING | CODEC_UTF8;
|
||||
hp.offset = get_reg(regs::rcx);
|
||||
return NewHook(hp, "Suika2_msvcrt");
|
||||
}
|
||||
bool Suika2::attach_function()
|
||||
{
|
||||
auto _1 = Suika2_msvcrt();
|
||||
return _1;
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
|
||||
|
||||
class Suika2:public ENGINE{
|
||||
public:
|
||||
Suika2(){
|
||||
is_engine_certain=false;
|
||||
check_by=CHECK_BY::FILE_ANY;
|
||||
check_by_target=check_by_list{L"suika.exe",L"conf/config.txt"};
|
||||
class Suika2 : public ENGINE
|
||||
{
|
||||
public:
|
||||
Suika2()
|
||||
{
|
||||
is_engine_certain = false;
|
||||
check_by = CHECK_BY::FILE_ANY;
|
||||
check_by_target = check_by_list{L"suika.exe", L"conf/config.txt"};
|
||||
};
|
||||
bool attach_function();
|
||||
bool attach_function();
|
||||
};
|
@ -1,25 +1,29 @@
|
||||
#include"TYPEMOON.h"
|
||||
namespace{
|
||||
bool _h() {
|
||||
//TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文
|
||||
BYTE bytes[]={
|
||||
0xBA,0x08,0xFF,0x00,0x00,
|
||||
0x41,0xB8,0x1C,0x20,0x00,0x00,
|
||||
0x66,0x90
|
||||
};
|
||||
auto addr=MemDbg::findBytes(bytes,sizeof(bytes),processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p",addr);
|
||||
if(addr==0)return false;
|
||||
addr=MemDbg::findEnclosingAlignedFunction(addr);ConsoleOutput("%p",addr);
|
||||
if(addr==0)return false;
|
||||
HookParam hp;
|
||||
hp.address=addr;
|
||||
hp.type=CODEC_UTF16|USING_STRING|EMBED_ABLE|EMBED_AFTER_NEW|EMBED_BEFORE_SIMPLE;
|
||||
hp.offset=get_reg(regs::r8);
|
||||
return NewHook(hp,"typemoon");
|
||||
#include "TYPEMOON.h"
|
||||
namespace
|
||||
{
|
||||
bool _h()
|
||||
{
|
||||
// TYPE-MOON 魔法使いの夜 多国語版 中文-英文-日文
|
||||
BYTE bytes[] = {
|
||||
0xBA, 0x08, 0xFF, 0x00, 0x00,
|
||||
0x41, 0xB8, 0x1C, 0x20, 0x00, 0x00,
|
||||
0x66, 0x90};
|
||||
auto addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
addr = MemDbg::findEnclosingAlignedFunction(addr);
|
||||
ConsoleOutput("%p", addr);
|
||||
if (addr == 0)
|
||||
return false;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = CODEC_UTF16 | USING_STRING | EMBED_ABLE | EMBED_AFTER_NEW | EMBED_BEFORE_SIMPLE;
|
||||
hp.offset = get_reg(regs::r8);
|
||||
return NewHook(hp, "typemoon");
|
||||
}
|
||||
}
|
||||
}
|
||||
bool TYPEMOON::attach_function() {
|
||||
bool TYPEMOON::attach_function()
|
||||
{
|
||||
return _h();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class TYPEMOON:public ENGINE{
|
||||
public:
|
||||
TYPEMOON(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"data*.hfa";
|
||||
};
|
||||
bool attach_function();
|
||||
class TYPEMOON : public ENGINE
|
||||
{
|
||||
public:
|
||||
TYPEMOON()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"data*.hfa";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include"V8.h"
|
||||
#include"v8/v8.h"
|
||||
#include "V8.h"
|
||||
#include "v8/v8.h"
|
||||
#if 0
|
||||
// Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write
|
||||
// sample game https://www.freem.ne.jp/dl/win/18963
|
||||
@ -113,7 +113,7 @@ namespace{
|
||||
}
|
||||
return save;
|
||||
}
|
||||
#if 0
|
||||
#if 0
|
||||
std::vector<HookParam> v8hook1(HMODULE module) {
|
||||
|
||||
const BYTE BYTES[] = {
|
||||
@ -155,7 +155,7 @@ namespace{
|
||||
}
|
||||
return save;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
bool innerHTML(HMODULE module) {
|
||||
//花葬
|
||||
//result = sub_142DF3CA0(a2, v5, 1u, (__int64)"innerHTML", a3);
|
||||
@ -208,8 +208,8 @@ namespace{
|
||||
}
|
||||
|
||||
#endif
|
||||
bool V8::attach_function_() {
|
||||
|
||||
return tryhookv8();
|
||||
}
|
||||
bool V8::attach_function_()
|
||||
{
|
||||
|
||||
return tryhookv8();
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
|
||||
|
||||
class V8:public ENGINE{
|
||||
public:
|
||||
V8(){
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
check_by_target=[this](){return attach_function_();};
|
||||
class V8 : public ENGINE
|
||||
{
|
||||
public:
|
||||
V8()
|
||||
{
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = [this]()
|
||||
{ return attach_function_(); };
|
||||
};
|
||||
bool attach_function_();
|
||||
bool attach_function(){return true;}
|
||||
bool attach_function_();
|
||||
bool attach_function() { return true; }
|
||||
};
|
||||
|
||||
|
@ -1,21 +1,22 @@
|
||||
#include"YOX.h"
|
||||
#include "YOX.h"
|
||||
bool YOX::attach_function()
|
||||
{
|
||||
const BYTE BYTES[] = {
|
||||
0x48,0x8B,0x0F,
|
||||
0x48,0x8d,0x54,0x24,0x50
|
||||
};
|
||||
0x48, 0x8B, 0x0F,
|
||||
0x48, 0x8d, 0x54, 0x24, 0x50};
|
||||
auto addrs = Util::SearchMemory(BYTES, sizeof(BYTES), PAGE_EXECUTE_READ, processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p %p", processStartAddress, processStopAddress);
|
||||
for (auto addr : addrs) {
|
||||
if (addr == 0)continue;
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
if (addr == 0)
|
||||
continue;
|
||||
HookParam hp;
|
||||
hp.address = addr;
|
||||
hp.type = USING_STRING ;
|
||||
hp.type = USING_STRING;
|
||||
hp.offset = get_stack(26);
|
||||
ConsoleOutput("yox64 %p", addr);
|
||||
return NewHook(hp, "yox64");
|
||||
}
|
||||
ConsoleOutput("yox64 failed");
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class YOX:public ENGINE{
|
||||
public:
|
||||
YOX(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"base/*.dat";
|
||||
};
|
||||
bool attach_function();
|
||||
class YOX : public ENGINE
|
||||
{
|
||||
public:
|
||||
YOX()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"base/*.dat";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,49 +1,50 @@
|
||||
#include "livecaptions.h"
|
||||
|
||||
|
||||
bool livecaptions::attach_function()
|
||||
{
|
||||
|
||||
// .text:0000000180001C98 push rbx
|
||||
// .text:0000000180001C9A sub rsp, 20h
|
||||
// .text:0000000180001C9E mov rbx, rcx
|
||||
// .text:0000000180001CA1 call memmove_0
|
||||
// .text:0000000180001CA6 mov rax, rbx
|
||||
// .text:0000000180001CA9 add rsp, 20h
|
||||
// .text:0000000180001CAD pop rbx
|
||||
// .text:0000000180001CAE retn
|
||||
HookParam hp;
|
||||
hp.address=(uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"),"memmove");
|
||||
hp.text_fun=[](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len){
|
||||
BYTE sig[]={
|
||||
0x40,0x53,0x48,0x83,0xEC,0x20,0x48,0x8B,0xD9,
|
||||
0xE8,XX4
|
||||
};
|
||||
auto a1=stack->retaddr-sizeof(sig);
|
||||
if((stack->retaddr>(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll")))
|
||||
if(memcmp((void*)a1,&sig,sizeof(sig)-4)==0){
|
||||
static std::set<uintptr_t>once;
|
||||
if(once.find(stack->retaddr)!=once.end())return;
|
||||
once.insert(stack->retaddr);
|
||||
// hp->text_fun=nullptr;
|
||||
// hp->type=HOOK_EMPTY;
|
||||
|
||||
HookParam hpinternal;
|
||||
hpinternal.address =a1;// 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
|
||||
hpinternal.type = USING_STRING | CODEC_UTF8|FULL_STRING;
|
||||
hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
// .text:0000000180001C98 push rbx
|
||||
// .text:0000000180001C9A sub rsp, 20h
|
||||
// .text:0000000180001C9E mov rbx, rcx
|
||||
// .text:0000000180001CA1 call memmove_0
|
||||
// .text:0000000180001CA6 mov rax, rbx
|
||||
// .text:0000000180001CA9 add rsp, 20h
|
||||
// .text:0000000180001CAD pop rbx
|
||||
// .text:0000000180001CAE retn
|
||||
HookParam hp;
|
||||
hp.address = (uintptr_t)GetProcAddress(GetModuleHandle(L"vcruntime140_app.dll"), "memmove");
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
BYTE sig[] = {
|
||||
0x40, 0x53, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, 0xD9,
|
||||
0xE8, XX4};
|
||||
auto a1 = stack->retaddr - sizeof(sig);
|
||||
if ((stack->retaddr > (uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll")))
|
||||
if (memcmp((void *)a1, &sig, sizeof(sig) - 4) == 0)
|
||||
{
|
||||
auto ptr = stack->rdx;
|
||||
auto size = stack->r8;
|
||||
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE) )//否则有短acsii
|
||||
static std::set<uintptr_t> once;
|
||||
if (once.find(stack->retaddr) != once.end())
|
||||
return;
|
||||
once.insert(stack->retaddr);
|
||||
// hp->text_fun=nullptr;
|
||||
// hp->type=HOOK_EMPTY;
|
||||
|
||||
HookParam hpinternal;
|
||||
hpinternal.address = a1; // 0xE551+(uintptr_t)GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
|
||||
hpinternal.type = USING_STRING | CODEC_UTF8 | FULL_STRING;
|
||||
hpinternal.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
*data = ptr;
|
||||
*len = size;
|
||||
}
|
||||
};
|
||||
NewHook(hpinternal, "std::_Char_traits<char,int>::copy(void *, const void *, size_t)");
|
||||
}
|
||||
auto ptr = stack->rdx;
|
||||
auto size = stack->r8;
|
||||
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE)) // 否则有短acsii
|
||||
{
|
||||
*data = ptr;
|
||||
*len = size;
|
||||
}
|
||||
};
|
||||
NewHook(hpinternal, "std::_Char_traits<char,int>::copy(void *, const void *, size_t)");
|
||||
}
|
||||
};
|
||||
|
||||
return NewHook(hp,"vcruntime140_app:memmove");
|
||||
|
||||
return NewHook(hp, "vcruntime140_app:memmove");
|
||||
}
|
@ -9,7 +9,7 @@ public:
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return GetModuleHandle(L"vcruntime140_app.dll")&&GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
|
||||
return GetModuleHandle(L"vcruntime140_app.dll") && GetModuleHandle(L"Microsoft.CognitiveServices.Speech.extension.embedded.sr.dll");
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class lucasystem:public ENGINE{
|
||||
public:
|
||||
lucasystem(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"files/*.PAK";
|
||||
};
|
||||
bool attach_function();
|
||||
class lucasystem : public ENGINE
|
||||
{
|
||||
public:
|
||||
lucasystem()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"files/*.PAK";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,82 +1,90 @@
|
||||
#include"mono.h"
|
||||
#include"mono/monocommon.hpp"
|
||||
|
||||
namespace{
|
||||
bool monobdwgc() {
|
||||
|
||||
#include "mono.h"
|
||||
#include "mono/monocommon.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool monobdwgc()
|
||||
{
|
||||
|
||||
HMODULE module = GetModuleHandleW(L"mono-2.0-bdwgc.dll");
|
||||
if (module == 0)return false;
|
||||
if (module == 0)
|
||||
return false;
|
||||
auto [minAddress, maxAddress] = Util::QueryModuleLimits(module);
|
||||
BYTE bytes[] = {
|
||||
0x81,0xF9,0x80,0x00,0x00,0x00,
|
||||
0x73,0x05,
|
||||
0x49,0x8B,0xCC
|
||||
/*
|
||||
_BYTE *__fastcall sub_18005B290(
|
||||
_WORD *a1,
|
||||
int a2,
|
||||
__int64 a3,
|
||||
_DWORD *a4,
|
||||
__int64 (__fastcall *a5)(__int64, __int64),
|
||||
__int64 a6,
|
||||
__int64 a7)
|
||||
0x81, 0xF9, 0x80, 0x00, 0x00, 0x00,
|
||||
0x73, 0x05,
|
||||
0x49, 0x8B, 0xCC
|
||||
/*
|
||||
_BYTE *__fastcall sub_18005B290(
|
||||
_WORD *a1,
|
||||
int a2,
|
||||
__int64 a3,
|
||||
_DWORD *a4,
|
||||
__int64 (__fastcall *a5)(__int64, __int64),
|
||||
__int64 a6,
|
||||
__int64 a7)
|
||||
|
||||
if ( (_DWORD)v26 )
|
||||
{
|
||||
if ( (unsigned int)v26 >= 0x80 )
|
||||
if ( (_DWORD)v26 )
|
||||
{
|
||||
if ( (unsigned int)v26 >= 0x800 )
|
||||
if ( (unsigned int)v26 >= 0x80 )
|
||||
{
|
||||
if ( (unsigned int)v26 >= 0x10000 )
|
||||
if ( (unsigned int)v26 >= 0x800 )
|
||||
{
|
||||
if ( (unsigned int)v26 >= 0x200000 )
|
||||
if ( (unsigned int)v26 >= 0x10000 )
|
||||
{
|
||||
if ( (unsigned int)v26 >= 0x4000000 )
|
||||
if ( (unsigned int)v26 >= 0x200000 )
|
||||
{
|
||||
v17 = 6i64;
|
||||
if ( (unsigned int)v26 >= 0x80000000 )
|
||||
*/
|
||||
if ( (unsigned int)v26 >= 0x4000000 )
|
||||
{
|
||||
v17 = 6i64;
|
||||
if ( (unsigned int)v26 >= 0x80000000 )
|
||||
*/
|
||||
};
|
||||
auto addrs =Util::SearchMemory(bytes, sizeof(bytes),PAGE_EXECUTE, minAddress, maxAddress);
|
||||
auto suc=false;
|
||||
for (auto addr : addrs) {
|
||||
const BYTE align[]={0xCC,0xCC,0xCC,0xCC};
|
||||
addr=reverseFindBytes(align,sizeof(align),addr-0x100,addr);
|
||||
if(addr==0)continue;
|
||||
|
||||
auto addrs = Util::SearchMemory(bytes, sizeof(bytes), PAGE_EXECUTE, minAddress, maxAddress);
|
||||
auto suc = false;
|
||||
for (auto addr : addrs)
|
||||
{
|
||||
const BYTE align[] = {0xCC, 0xCC, 0xCC, 0xCC};
|
||||
addr = reverseFindBytes(align, sizeof(align), addr - 0x100, addr);
|
||||
if (addr == 0)
|
||||
continue;
|
||||
|
||||
ConsoleOutput("monobdwgcdll %p", addr);
|
||||
HookParam hp;
|
||||
hp.address = addr+4;
|
||||
hp.offset=get_reg(regs::rcx);
|
||||
hp.type = CODEC_UTF16|USING_STRING;
|
||||
hp.text_fun=[](auto, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
|
||||
std::wstring str = std::wstring((LPWSTR)*data );
|
||||
*split=str.find(L"OnShowComplete")!=str.npos;
|
||||
|
||||
*len = wcslen((wchar_t*)*data) * 2 ;
|
||||
hp.address = addr + 4;
|
||||
hp.offset = get_reg(regs::rcx);
|
||||
hp.type = CODEC_UTF16 | USING_STRING;
|
||||
hp.text_fun = [](auto, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
std::wstring str = std::wstring((LPWSTR)*data);
|
||||
*split = str.find(L"OnShowComplete") != str.npos;
|
||||
|
||||
*len = wcslen((wchar_t *)*data) * 2;
|
||||
};
|
||||
hp.filter_fun=[](void* data, size_t* len, HookParam* hp){
|
||||
std::wstring str = std::wstring((LPWSTR)data ,*len/2);
|
||||
if(str.find(L"OnShowComplete")!=str.npos){
|
||||
hp.filter_fun = [](void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
std::wstring str = std::wstring((LPWSTR)data, *len / 2);
|
||||
if (str.find(L"OnShowComplete") != str.npos)
|
||||
{
|
||||
str = std::regex_replace(str, std::wregex(L"\n"), L"");
|
||||
std::wregex reg1(L"\\((.*?)\\)");
|
||||
std::wsmatch match;
|
||||
std::regex_search(str, match,reg1 );
|
||||
auto result1= match[1].str();
|
||||
|
||||
std::regex_search(str, match,std::wregex(L" Text:(.*?)Next:(.*?)") );
|
||||
result1= match[1].str();
|
||||
write_string_overwrite(data,len,result1);
|
||||
std::wsmatch match;
|
||||
std::regex_search(str, match, reg1);
|
||||
auto result1 = match[1].str();
|
||||
|
||||
std::regex_search(str, match, std::wregex(L" Text:(.*?)Next:(.*?)"));
|
||||
result1 = match[1].str();
|
||||
write_string_overwrite(data, len, result1);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
suc|=NewHook(hp, "monobdwgcdll");
|
||||
suc |= NewHook(hp, "monobdwgcdll");
|
||||
}
|
||||
return suc;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool mono::attach_function(){
|
||||
bool common=monocommon::hook_mono_il2cpp();
|
||||
bool mono::attach_function()
|
||||
{
|
||||
bool common = monocommon::hook_mono_il2cpp();
|
||||
return common;
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
|
||||
|
||||
class mono:public ENGINE{
|
||||
public:
|
||||
mono(){
|
||||
|
||||
check_by=CHECK_BY::ALL_TRUE;
|
||||
class mono : public ENGINE
|
||||
{
|
||||
public:
|
||||
mono()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::ALL_TRUE;
|
||||
};
|
||||
bool attach_function();
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,12 +1,16 @@
|
||||
#include"pchooks.h"
|
||||
|
||||
bool pchooks::attach_function() {
|
||||
for (std::wstring DXVersion : { L"d3dx9", L"d3dx10" })
|
||||
if (HMODULE module = GetModuleHandleW(DXVersion.c_str())) PcHooks::hookD3DXFunctions(module);
|
||||
else for (int i = 0; i < 50; ++i)
|
||||
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str())) PcHooks::hookD3DXFunctions(module);
|
||||
#include "pchooks.h"
|
||||
|
||||
bool pchooks::attach_function()
|
||||
{
|
||||
for (std::wstring DXVersion : {L"d3dx9", L"d3dx10"})
|
||||
if (HMODULE module = GetModuleHandleW(DXVersion.c_str()))
|
||||
PcHooks::hookD3DXFunctions(module);
|
||||
else
|
||||
for (int i = 0; i < 50; ++i)
|
||||
if (HMODULE module = GetModuleHandleW((DXVersion + L"_" + std::to_wstring(i)).c_str()))
|
||||
PcHooks::hookD3DXFunctions(module);
|
||||
|
||||
PcHooks::hookGDIFunctions();
|
||||
PcHooks::hookGDIPlusFunctions();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
|
||||
|
||||
class pchooks:public ENGINE{
|
||||
public:
|
||||
pchooks(){
|
||||
|
||||
check_by=CHECK_BY::ALL_TRUE;
|
||||
dontstop=true;
|
||||
};
|
||||
bool attach_function();
|
||||
class pchooks : public ENGINE
|
||||
{
|
||||
public:
|
||||
pchooks()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::ALL_TRUE;
|
||||
dontstop = true;
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include"rpcs3.h"
|
||||
namespace{
|
||||
#if 0 //only support0.0.20-0.0.27
|
||||
#include "rpcs3.h"
|
||||
namespace
|
||||
{
|
||||
#if 0 // only support0.0.20-0.0.27
|
||||
int emoffset;
|
||||
int jitoffset;
|
||||
uintptr_t getDoJitAddress_() {
|
||||
@ -113,10 +114,11 @@ namespace{
|
||||
|
||||
return DoJitPtr+6;
|
||||
}
|
||||
#endif
|
||||
|
||||
uintptr_t getDoJitAddress() {
|
||||
//rpcs3/Emu/Cell/PPUThread.cpp
|
||||
#endif
|
||||
|
||||
uintptr_t getDoJitAddress()
|
||||
{
|
||||
// rpcs3/Emu/Cell/PPUThread.cpp
|
||||
/*
|
||||
extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = nullptr)
|
||||
{
|
||||
@ -138,130 +140,147 @@ namespace{
|
||||
}
|
||||
……
|
||||
*/
|
||||
char log[]="ppu_register_function_at(0x%x): empty range";
|
||||
auto logstrptr=MemDbg::findBytes(log,sizeof(log),processStartAddress,processStopAddress);
|
||||
ConsoleOutput("%p",logstrptr);
|
||||
if(logstrptr==0)return 0;
|
||||
auto addr=MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p",addr);
|
||||
if(addr==0)return 0;
|
||||
//ff cc cc cc,find不到。。
|
||||
BYTE start[]={XX,0xCC,0xCC,0xCC};
|
||||
addr=reverseFindBytes(start,sizeof(start),addr-0x200,addr,4,true);
|
||||
ConsoleOutput("%p",addr);
|
||||
char log[] = "ppu_register_function_at(0x%x): empty range";
|
||||
auto logstrptr = MemDbg::findBytes(log, sizeof(log), processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p", logstrptr);
|
||||
if (logstrptr == 0)
|
||||
return 0;
|
||||
auto addr = MemDbg::findleaaddr(logstrptr, processStartAddress, processStopAddress);
|
||||
ConsoleOutput("%p", addr);
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
// ff cc cc cc,find不到。。
|
||||
BYTE start[] = {XX, 0xCC, 0xCC, 0xCC};
|
||||
addr = reverseFindBytes(start, sizeof(start), addr - 0x200, addr, 4, true);
|
||||
ConsoleOutput("%p", addr);
|
||||
return addr;
|
||||
|
||||
}
|
||||
struct emfuncinfo{
|
||||
uint64_t type;
|
||||
int argidx;int padding;
|
||||
void* hookfunc;
|
||||
void* filterfun;
|
||||
const char* _id;
|
||||
};
|
||||
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
|
||||
|
||||
bool checkiscurrentgame(const emfuncinfo& em){
|
||||
auto wininfos=get_proc_windows();
|
||||
for(auto&& info:wininfos){
|
||||
if(info.title.find(acastw(em._id))!=info.title.npos)return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::set<std::pair<uintptr_t,uintptr_t>> timeoutbreaks;
|
||||
|
||||
void dohookemaddr(uintptr_t em_address,uintptr_t ret){
|
||||
jitaddraddr(em_address,ret,JITTYPE::RPCS3);
|
||||
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return;
|
||||
if(!(checkiscurrentgame(emfunctionhooks.at(em_address))))return;
|
||||
timeoutbreaks.insert(std::make_pair(em_address,ret));
|
||||
auto op=emfunctionhooks.at(em_address);
|
||||
HookParam hpinternal;
|
||||
hpinternal.address=ret;
|
||||
hpinternal.emu_addr=em_address;//用于生成hcode
|
||||
hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type;
|
||||
hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc;
|
||||
hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun;
|
||||
hpinternal.argidx=op.argidx;
|
||||
hpinternal.padding=op.padding;
|
||||
hpinternal.jittype=JITTYPE::RPCS3;
|
||||
NewHook(hpinternal,op._id);
|
||||
}
|
||||
|
||||
bool unsafeinithooks(){
|
||||
//rpcs0.0.30,不知道为什么ppu_register_function_at不全。不过看代码得到映射表了,直接弄吧。
|
||||
//rpcs3/Emu/Cell/PPUThread.cpp
|
||||
// Get pointer to executable cache
|
||||
/*
|
||||
static inline u8* ppu_ptr(u32 addr)
|
||||
struct emfuncinfo
|
||||
{
|
||||
return vm::g_exec_addr + u64{addr} * 2;
|
||||
}
|
||||
*/
|
||||
HookParam hp;
|
||||
hp.type=DIRECT_READ;
|
||||
hp.address=0x500000000;
|
||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
|
||||
{
|
||||
for(auto [addr,info]:emfunctionhooks){
|
||||
auto table=addr*2+0x500000000;
|
||||
if(IsBadReadPtr((void*)table,sizeof(uintptr_t)))continue;
|
||||
auto funcaddr=*(uintptr_t*)table;
|
||||
funcaddr&=0x0000ffffffffffff;
|
||||
if(!funcaddr)continue;
|
||||
auto p=std::make_pair(addr,funcaddr);
|
||||
if(timeoutbreaks.find(p)!=timeoutbreaks.end())continue;
|
||||
dohookemaddr(addr,funcaddr);
|
||||
delayinsertNewHook(addr);
|
||||
uint64_t type;
|
||||
int argidx;
|
||||
int padding;
|
||||
void *hookfunc;
|
||||
void *filterfun;
|
||||
const char *_id;
|
||||
};
|
||||
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
|
||||
|
||||
bool checkiscurrentgame(const emfuncinfo &em)
|
||||
{
|
||||
auto wininfos = get_proc_windows();
|
||||
for (auto &&info : wininfos)
|
||||
{
|
||||
if (info.title.find(acastw(em._id)) != info.title.npos)
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return NewHook(hp,"g_exec_addr");
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::set<std::pair<uintptr_t, uintptr_t>> timeoutbreaks;
|
||||
|
||||
void dohookemaddr(uintptr_t em_address, uintptr_t ret)
|
||||
{
|
||||
jitaddraddr(em_address, ret, JITTYPE::RPCS3);
|
||||
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
|
||||
return;
|
||||
if (!(checkiscurrentgame(emfunctionhooks.at(em_address))))
|
||||
return;
|
||||
timeoutbreaks.insert(std::make_pair(em_address, ret));
|
||||
auto op = emfunctionhooks.at(em_address);
|
||||
HookParam hpinternal;
|
||||
hpinternal.address = ret;
|
||||
hpinternal.emu_addr = em_address; // 用于生成hcode
|
||||
hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
|
||||
hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc;
|
||||
hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun;
|
||||
hpinternal.argidx = op.argidx;
|
||||
hpinternal.padding = op.padding;
|
||||
hpinternal.jittype = JITTYPE::RPCS3;
|
||||
NewHook(hpinternal, op._id);
|
||||
}
|
||||
|
||||
bool unsafeinithooks()
|
||||
{
|
||||
// rpcs0.0.30,不知道为什么ppu_register_function_at不全。不过看代码得到映射表了,直接弄吧。
|
||||
// rpcs3/Emu/Cell/PPUThread.cpp
|
||||
// Get pointer to executable cache
|
||||
/*
|
||||
static inline u8* ppu_ptr(u32 addr)
|
||||
{
|
||||
return vm::g_exec_addr + u64{addr} * 2;
|
||||
}
|
||||
*/
|
||||
HookParam hp;
|
||||
hp.type = DIRECT_READ;
|
||||
hp.address = 0x500000000;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
for (auto [addr, info] : emfunctionhooks)
|
||||
{
|
||||
auto table = addr * 2 + 0x500000000;
|
||||
if (IsBadReadPtr((void *)table, sizeof(uintptr_t)))
|
||||
continue;
|
||||
auto funcaddr = *(uintptr_t *)table;
|
||||
funcaddr &= 0x0000ffffffffffff;
|
||||
if (!funcaddr)
|
||||
continue;
|
||||
auto p = std::make_pair(addr, funcaddr);
|
||||
if (timeoutbreaks.find(p) != timeoutbreaks.end())
|
||||
continue;
|
||||
dohookemaddr(addr, funcaddr);
|
||||
delayinsertNewHook(addr);
|
||||
}
|
||||
};
|
||||
return NewHook(hp, "g_exec_addr");
|
||||
}
|
||||
}
|
||||
bool rpcs3::attach_function()
|
||||
{
|
||||
ConsoleOutput("[Compatibility] RPCS3");
|
||||
auto DoJitPtr=getDoJitAddress();
|
||||
if(DoJitPtr==0)return false;
|
||||
ConsoleOutput("[Compatibility] RPCS3");
|
||||
auto DoJitPtr = getDoJitAddress();
|
||||
if (DoJitPtr == 0)
|
||||
return false;
|
||||
unsafeinithooks();
|
||||
spDefault.jittype=JITTYPE::RPCS3;
|
||||
spDefault.jittype = JITTYPE::RPCS3;
|
||||
spDefault.minAddress = 0;
|
||||
spDefault.maxAddress = -1;
|
||||
HookParam hp;
|
||||
hp.address=DoJitPtr;
|
||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
|
||||
auto em_address =stack->rcx;// *(uint32_t*)*(uintptr_t*)(stack->base+emoffset);
|
||||
auto entrypoint=stack->r8;//*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
|
||||
if(!em_address||!entrypoint)return;
|
||||
dohookemaddr(em_address,entrypoint);
|
||||
hp.address = DoJitPtr;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto em_address = stack->rcx; // *(uint32_t*)*(uintptr_t*)(stack->base+emoffset);
|
||||
auto entrypoint = stack->r8; //*(uintptr_t*)*(uintptr_t*)(stack->base+jitoffset)-0x0008000000000000;
|
||||
if (!em_address || !entrypoint)
|
||||
return;
|
||||
dohookemaddr(em_address, entrypoint);
|
||||
delayinsertNewHook(em_address);
|
||||
};
|
||||
return NewHook(hp,"vita3kjit");
|
||||
return NewHook(hp, "vita3kjit");
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
namespace{
|
||||
bool FBLJM61131(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
std::regex pattern("\\[[^\\]]+.");
|
||||
s = std::regex_replace(s, pattern, "");
|
||||
s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), "");
|
||||
s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), "");
|
||||
s = std::regex_replace(s, std::regex("\\n+"), " ");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
auto _ = []()
|
||||
{
|
||||
emfunctionhooks = {
|
||||
//'&' -Sora no Mukou de Sakimasu you ni-
|
||||
{0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}},
|
||||
// Dunamis15
|
||||
{0x42c90, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM60347"}},
|
||||
|
||||
bool FBLJM61131(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
std::regex pattern("\\[[^\\]]+.");
|
||||
s = std::regex_replace(s, pattern, "");
|
||||
s = std::regex_replace(s, std::regex("\\\\k|\\\\x|%C|%B"), "");
|
||||
s = std::regex_replace(s, std::regex("\\%\\d+\\#[0-9a-fA-F]*\\;"), "");
|
||||
s = std::regex_replace(s, std::regex("\\n+"), " ");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
auto _=[](){
|
||||
emfunctionhooks={
|
||||
//'&' -Sora no Mukou de Sakimasu you ni-
|
||||
{0x46328,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM61131"}},
|
||||
//Dunamis15
|
||||
{0x42c90,{CODEC_UTF8,1,0,0,FBLJM61131,"BLJM60347"}},
|
||||
|
||||
};
|
||||
return 1;
|
||||
}();
|
||||
};
|
||||
return 1;
|
||||
}();
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class rpcs3:public ENGINE{
|
||||
public:
|
||||
rpcs3(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"rpcs3.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
class rpcs3 : public ENGINE
|
||||
{
|
||||
public:
|
||||
rpcs3()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"rpcs3.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -1,12 +1,15 @@
|
||||
#include"vita3k.h"
|
||||
namespace{
|
||||
#include "vita3k.h"
|
||||
namespace
|
||||
{
|
||||
auto isVirtual = true;
|
||||
auto idxDescriptor = isVirtual == true ? 2 : 1;
|
||||
auto idxEntrypoint = idxDescriptor + 1;
|
||||
uintptr_t getDoJitAddress() {
|
||||
uintptr_t getDoJitAddress()
|
||||
{
|
||||
auto RegisterBlockSig1 = "40 55 53 56 57 41 54 41 56 41 57 48 8D 6C 24 E9 48 81 EC 90 00 00 00 48 8B ?? ?? ?? ?? ?? 48 33 C4 48 89 45 07 4D 8B F1 49 8B F0 48 8B FA 48 8B D9 4C 8B 7D 77 48 8B 01 48 8D 55 C7 FF 50 10";
|
||||
auto first=find_pattern(RegisterBlockSig1,processStartAddress,processStopAddress);
|
||||
if (first) return first;
|
||||
auto first = find_pattern(RegisterBlockSig1, processStartAddress, processStopAddress);
|
||||
if (first)
|
||||
return first;
|
||||
/*
|
||||
// DebugSymbol: RegisterBlock
|
||||
// ?RegisterBlock@EmitX64@X64@Backend@Dynarmic@@IEAA?AUBlockDescriptor@1234@AEBVLocationDescriptor@IR@4@PEBX_K@Z <- new
|
||||
@ -19,346 +22,544 @@ namespace{
|
||||
return symbols[0];
|
||||
}
|
||||
*/
|
||||
auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57";// "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57";
|
||||
first = find_pattern(PatchBlockSig1,processStartAddress,processStopAddress);
|
||||
if (first) {
|
||||
auto PatchBlockSig1 = "4C 8B DC 49 89 5B 10 49 89 6B 18 56 57 41 54 41 56 41 57"; // "4C 8B DC 49 89 5B ?? 49 89 6B ?? 56 57 41 54 41 56 41 57";
|
||||
first = find_pattern(PatchBlockSig1, processStartAddress, processStopAddress);
|
||||
if (first)
|
||||
{
|
||||
idxDescriptor = 1;
|
||||
idxEntrypoint = 2;
|
||||
return first;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
struct emfuncinfo{
|
||||
uint64_t type;
|
||||
int argidx;int padding;
|
||||
void* hookfunc;
|
||||
void* filterfun;
|
||||
const char* _id;
|
||||
};
|
||||
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
|
||||
struct emfuncinfo
|
||||
{
|
||||
uint64_t type;
|
||||
int argidx;
|
||||
int padding;
|
||||
void *hookfunc;
|
||||
void *filterfun;
|
||||
const char *_id;
|
||||
};
|
||||
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
|
||||
|
||||
bool checkiscurrentgame(const emfuncinfo& em){
|
||||
auto wininfos=get_proc_windows();
|
||||
for(auto&& info:wininfos){
|
||||
if(info.title.find(acastw(em._id))!=info.title.npos)return true;
|
||||
bool checkiscurrentgame(const emfuncinfo &em)
|
||||
{
|
||||
auto wininfos = get_proc_windows();
|
||||
for (auto &&info : wininfos)
|
||||
{
|
||||
if (info.title.find(acastw(em._id)) != info.title.npos)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool vita3k::attach_function()
|
||||
{
|
||||
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+");
|
||||
auto DoJitPtr=getDoJitAddress();
|
||||
if(DoJitPtr==0)return false;
|
||||
ConsoleOutput("DoJitPtr %p",DoJitPtr);
|
||||
spDefault.jittype=JITTYPE::VITA3K;
|
||||
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3520+");
|
||||
auto DoJitPtr = getDoJitAddress();
|
||||
if (DoJitPtr == 0)
|
||||
return false;
|
||||
ConsoleOutput("DoJitPtr %p", DoJitPtr);
|
||||
spDefault.jittype = JITTYPE::VITA3K;
|
||||
spDefault.minAddress = 0;
|
||||
spDefault.maxAddress = -1;
|
||||
HookParam hp;
|
||||
hp.address=DoJitPtr;
|
||||
hp.text_fun=[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto descriptor = *argidx(stack,idxDescriptor+1); // r8
|
||||
auto entrypoint = *argidx(stack,idxEntrypoint+1); // r9
|
||||
auto em_address = *(uint32_t*)descriptor;
|
||||
if(!entrypoint)return;
|
||||
// ConsoleOutput("%p",em_address);
|
||||
jitaddraddr(em_address,entrypoint,JITTYPE::VITA3K);
|
||||
[&](){
|
||||
if(emfunctionhooks.find(em_address)==emfunctionhooks.end())return;
|
||||
auto op=emfunctionhooks.at(em_address);
|
||||
if(!(checkiscurrentgame(op)))return;
|
||||
|
||||
HookParam hpinternal;
|
||||
hpinternal.address=entrypoint;
|
||||
hpinternal.emu_addr=em_address;//用于生成hcode
|
||||
hpinternal.type=USING_STRING|NO_CONTEXT|BREAK_POINT|op.type;
|
||||
hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc;
|
||||
hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun;
|
||||
hpinternal.argidx=op.argidx;
|
||||
hpinternal.padding=op.padding;
|
||||
hpinternal.jittype=JITTYPE::VITA3K;
|
||||
NewHook(hpinternal,op._id);
|
||||
}();
|
||||
delayinsertNewHook(em_address);
|
||||
hp.address = DoJitPtr;
|
||||
hp.text_fun = [](hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto descriptor = *argidx(stack, idxDescriptor + 1); // r8
|
||||
auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9
|
||||
auto em_address = *(uint32_t *)descriptor;
|
||||
if (!entrypoint)
|
||||
return;
|
||||
// ConsoleOutput("%p",em_address);
|
||||
jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K);
|
||||
[&]()
|
||||
{
|
||||
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
|
||||
return;
|
||||
auto op = emfunctionhooks.at(em_address);
|
||||
if (!(checkiscurrentgame(op)))
|
||||
return;
|
||||
|
||||
HookParam hpinternal;
|
||||
hpinternal.address = entrypoint;
|
||||
hpinternal.emu_addr = em_address; // 用于生成hcode
|
||||
hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
|
||||
hpinternal.text_fun = (decltype(hpinternal.text_fun))op.hookfunc;
|
||||
hpinternal.filter_fun = (decltype(hpinternal.filter_fun))op.filterfun;
|
||||
hpinternal.argidx = op.argidx;
|
||||
hpinternal.padding = op.padding;
|
||||
hpinternal.jittype = JITTYPE::VITA3K;
|
||||
NewHook(hpinternal, op._id);
|
||||
}();
|
||||
delayinsertNewHook(em_address);
|
||||
};
|
||||
return NewHook(hp,"vita3kjit");
|
||||
return NewHook(hp, "vita3kjit");
|
||||
}
|
||||
|
||||
|
||||
namespace{
|
||||
bool FPCSG01023(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("<br>"), "");
|
||||
s = std::regex_replace(s, std::regex("%CF11F"), "");
|
||||
s = std::regex_replace(s, std::regex("%CFFFF"), "");
|
||||
s = std::regex_replace(s, std::regex("%K%P"), "");
|
||||
s = std::regex_replace(s, std::regex("%K%N"), "");
|
||||
s = std::regex_replace(s, std::regex("\n"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
template<int idx>
|
||||
bool FPCSG01282(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("(\\n)+"), " ");
|
||||
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
|
||||
static std::string last;
|
||||
if(last==s)return false;
|
||||
last=s;
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
|
||||
template<int index>
|
||||
void ReadU16TextAndLenDW(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address=VITA3K::emu_arg(stack)[index];
|
||||
*len=(*(DWORD*)(address+0x8))*2;
|
||||
*data=address+0xC;
|
||||
}
|
||||
|
||||
bool FPCSG00410(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#n"), " ");
|
||||
// .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【")
|
||||
// .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・")
|
||||
strReplace(s,"\x87\x43","!?");strReplace(s,"\x87\x41","!!");strReplace(s,"\x87\x45","\x81\x42");strReplace(s,"\x87\x4a","\x81\x79");
|
||||
strReplace(s,"\x87\x4b","\x81\x7a");strReplace(s,"\x87\x44","\x81\x41");strReplace(s,"\x87\x40","\x81\x45\x81\x45\x81\x45");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00448(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG01008(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), " ");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
void TPCSG00903(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address=VITA3K::emu_arg(stack)[0];
|
||||
*len=(*(DWORD*)(address+0x14));
|
||||
*data=address+0x1C;
|
||||
}
|
||||
bool FPCSG00903(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("\\\\n"), " ");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00839(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::wstring((wchar_t*)data,*len/2);
|
||||
s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L"");
|
||||
s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L"");
|
||||
s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1");
|
||||
s = std::regex_replace(s, std::wregex(L"\\\\n"), L"");
|
||||
static std::wstring last;
|
||||
if(last.find(s)!=last.npos)return false;
|
||||
last=s;
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00751(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("@[a-z]"), "");
|
||||
//s = std::regex_replace(s, std::regex("$"), "");
|
||||
strReplace(s,"\x81\x90","");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00706(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::wstring((wchar_t*)data,*len/2);
|
||||
s = std::regex_replace(s, std::wregex(L"<br>"), L"");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00696(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
//.replace(/㌔/g, '⁉')
|
||||
//.replace(/㍉/g, '!!')
|
||||
strReplace(s,"\x87\x60","");
|
||||
strReplace(s,"\x87\x5f","");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00389(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00216(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool FPCSG00405(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
bool PCSG00776(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
auto ws=StringToWideString(s,932).value();
|
||||
strReplace(ws,L"\x02",L"");
|
||||
Trim(ws);
|
||||
return write_string_overwrite(data,len,WideStringToString(ws));
|
||||
}
|
||||
|
||||
void PCSG00911(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address = VITA3K::emu_arg(stack)[1];
|
||||
std::string final_string = "";
|
||||
BYTE pattern[] = {0x47,0xff,0xff};
|
||||
auto results = MemDbg::findBytes(pattern,sizeof(pattern),address,address+0x50);
|
||||
if (!results) return;
|
||||
|
||||
address = results+5;
|
||||
|
||||
while (true) {
|
||||
std::string text= (char*)address;
|
||||
final_string += text;
|
||||
address = address+(text.size() + 1);
|
||||
|
||||
auto bytes=(BYTE*)address;
|
||||
|
||||
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break;
|
||||
address = address+(3);
|
||||
bytes=(BYTE*)address;
|
||||
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF)) break;
|
||||
|
||||
address = address+(5);
|
||||
|
||||
namespace
|
||||
{
|
||||
bool FPCSG01023(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("<br>"), "");
|
||||
s = std::regex_replace(s, std::regex("%CF11F"), "");
|
||||
s = std::regex_replace(s, std::regex("%CFFFF"), "");
|
||||
s = std::regex_replace(s, std::regex("%K%P"), "");
|
||||
s = std::regex_replace(s, std::regex("%K%N"), "");
|
||||
s = std::regex_replace(s, std::regex("\n"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
template <int idx>
|
||||
bool FPCSG01282(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("(\\n)+"), " ");
|
||||
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
|
||||
static std::string last;
|
||||
if (last == s)
|
||||
return false;
|
||||
last = s;
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
write_string_new(data,len,final_string);
|
||||
}
|
||||
void TPCSG00291(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto a2= VITA3K::emu_arg(stack)[0];
|
||||
|
||||
auto vm = *(DWORD*)(a2+(0x28));
|
||||
vm=*(DWORD*)VITA3K::emu_addr(stack,vm);
|
||||
vm=*(DWORD*)VITA3K::emu_addr(stack,vm+8);
|
||||
uintptr_t address=VITA3K::emu_addr(stack,vm);
|
||||
auto len1=*(DWORD*)(address+4);
|
||||
auto p=address+0x20;
|
||||
if(len1>4 && *(WORD*)(p+2)==0){
|
||||
auto p1=*(DWORD*)(address+8);
|
||||
vm=*(DWORD*)VITA3K::emu_addr(stack,vm);
|
||||
vm=*(DWORD*)VITA3K::emu_addr(stack,vm+0xC);
|
||||
p=VITA3K::emu_addr(stack,vm);
|
||||
}
|
||||
static int fm=0;
|
||||
static std::string pre;
|
||||
auto b=fm;
|
||||
auto s=[](uintptr_t address){
|
||||
auto frist = *(WORD*)address;
|
||||
auto lo = frist & 0xFF; // uppercase: 41->5A
|
||||
auto hi = frist >> 8;
|
||||
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) {
|
||||
return std::string();
|
||||
}
|
||||
std::string s ;int i = 0;WORD c;
|
||||
char buf[3]={0};
|
||||
while ((c = *(WORD*)(address+i)) != 0) {
|
||||
// reverse endian: ShiftJIS BE => LE
|
||||
buf[0] = c >> 8;
|
||||
buf[1] = c & 0xFF;
|
||||
template <int index>
|
||||
void ReadU16TextAndLenDW(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto address = VITA3K::emu_arg(stack)[index];
|
||||
*len = (*(DWORD *)(address + 0x8)) * 2;
|
||||
*data = address + 0xC;
|
||||
}
|
||||
|
||||
if (c == 0x815e /* / */) {
|
||||
s += ' '; // single line
|
||||
}
|
||||
else if (buf[0] == 0) {
|
||||
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
|
||||
//// 4e00 6d00=>PLAYER
|
||||
// do nothing
|
||||
if (buf[1] == 0x4e) {
|
||||
s += "PLAYER";
|
||||
fm++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
s+=buf;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
return s;
|
||||
}(p);
|
||||
if(b>0){
|
||||
fm--;
|
||||
return;
|
||||
}
|
||||
if(s==pre)return ;
|
||||
pre=s;
|
||||
write_string_new(data,len,s);
|
||||
}
|
||||
bool FPCSG00410(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#n"), " ");
|
||||
// .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【")
|
||||
// .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・")
|
||||
strReplace(s, "\x87\x43", "!?");
|
||||
strReplace(s, "\x87\x41", "!!");
|
||||
strReplace(s, "\x87\x45", "\x81\x42");
|
||||
strReplace(s, "\x87\x4a", "\x81\x79");
|
||||
strReplace(s, "\x87\x4b", "\x81\x7a");
|
||||
strReplace(s, "\x87\x44", "\x81\x41");
|
||||
strReplace(s, "\x87\x40", "\x81\x45\x81\x45\x81\x45");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00448(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG01008(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), " ");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
void TPCSG00903(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto address = VITA3K::emu_arg(stack)[0];
|
||||
*len = (*(DWORD *)(address + 0x14));
|
||||
*data = address + 0x1C;
|
||||
}
|
||||
bool FPCSG00903(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("\\\\n"), " ");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG01180(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"(\\n)"), " ");
|
||||
s = std::regex_replace(s, std::regex(R"(,.*$)"), " ");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00839(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::wstring((wchar_t *)data, *len / 2);
|
||||
s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L"");
|
||||
s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L"");
|
||||
s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1");
|
||||
s = std::regex_replace(s, std::wregex(L"\\\\n"), L"");
|
||||
static std::wstring last;
|
||||
if (last.find(s) != last.npos)
|
||||
return false;
|
||||
last = s;
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00751(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("@[a-z]"), "");
|
||||
// s = std::regex_replace(s, std::regex("$"), "");
|
||||
strReplace(s, "\x81\x90", "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00401(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"([\s])"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(\c)"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(\\n)"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00912(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("%N"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00706(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::wstring((wchar_t *)data, *len / 2);
|
||||
s = std::regex_replace(s, std::wregex(L"<br>"), L"");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00696(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
//.replace(/㌔/g, '⁉')
|
||||
//.replace(/㍉/g, '!!')
|
||||
strReplace(s, "\x87\x60", "");
|
||||
strReplace(s, "\x87\x5f", "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00389(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00216(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
s = std::regex_replace(s, std::regex("(#n)+"), "");
|
||||
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
|
||||
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00405(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex("[\\s]"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool PCSG00776(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
auto ws = StringToWideString(s, 932).value();
|
||||
strReplace(ws, L"\x02", L"");
|
||||
Trim(ws);
|
||||
return write_string_overwrite(data, len, WideStringToString(ws));
|
||||
}
|
||||
void PCSG00912(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto address = VITA3K::emu_arg(stack)[1];
|
||||
std::string final_string = "";
|
||||
BYTE pattern[] = {0x47, 0xff, 0xff};
|
||||
auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50);
|
||||
if (!results)
|
||||
return;
|
||||
|
||||
auto _=[](){
|
||||
emfunctionhooks={
|
||||
//Tsuihou Senkyo
|
||||
{0x8002e176,{0,0,0,0,FPCSG01023,"PCSG01023"}},//dialogue+name,sjis
|
||||
//死神と少女 Shinigami to Shoujo
|
||||
{0x800204ba,{0,2,0,0,FPCSG01282<0>,"PCSG01282"}},//dialogueNVL,sjis
|
||||
{0x8000f00e,{0,1,0,0,FPCSG01282<1>,"PCSG01282"}},//dialogue main
|
||||
{0x80011f1a,{0,0,0,0,FPCSG01282<2>,"PCSG01282"}},//Name
|
||||
{0x8001ebac,{0,1,0,0,FPCSG01282<3>,"PCSG01282"}},//choices
|
||||
//神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri
|
||||
{0x828bb50c,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//dialogue
|
||||
{0x828ba9b6,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,0,"PCSG01268"}},//name
|
||||
{0x8060D376,{CODEC_UTF8,0,0,0,0,"PCSG01268"}},//vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason.
|
||||
//Sanzen Sekai Yuugi ~MultiUniverse Myself~
|
||||
{0x8005ae24,{0,0,0,0,0,"PCSG01194"}},//dialouge+name,sjis,need remap jis char,to complex
|
||||
// Marginal #4 Road to Galaxy
|
||||
{0x8002ff90,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG01008"}},//text
|
||||
//BLACK WOLVES SAGA -Weiβ und Schwarz-
|
||||
// {0x8004ed22,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//name
|
||||
// {0x8006d202,{CODEC_UTF8,1,2,0,FPCSG01008,"PCSG00935"}},//text
|
||||
{0x800581a2,{CODEC_UTF8,0,0,0,FPCSG01008,"PCSG00935"}},//text
|
||||
//New Game! The Challenge Stage!
|
||||
{0x8012674c,{CODEC_UTF8,0,0,TPCSG00903,FPCSG00903,"PCSG00903"}},
|
||||
//Kenka Banchou Otome
|
||||
{0x80009722,{CODEC_UTF16,0,0,0,FPCSG00839,"PCSG00839"}},
|
||||
//Arcana famiglia -La storia della Arcana Famiglia-
|
||||
{0x80070e30,{0,2,0,0,FPCSG00751,"PCSG00751"}},//all,sjis
|
||||
{0x80070cdc,{0,1,0,0,FPCSG00751,"PCSG00751"}},//text
|
||||
//もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba.
|
||||
{0x80c1f270,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//dialogue
|
||||
{0x80d48bfc,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<1>,FPCSG00706,"PCSG00706"}},//Dictionary1
|
||||
{0x80d48c20,{CODEC_UTF16,0,0,ReadU16TextAndLenDW<0>,FPCSG00706,"PCSG00706"}},//Dictionary2
|
||||
//Angelique Retour
|
||||
{0x8008bd1a,{0,1,0,0,FPCSG00696,"PCSG00696"}},//text1,sjis
|
||||
{0x8008cd48,{0,0,0,0,FPCSG00696,"PCSG00696"}},//text2
|
||||
{0x8008f75a,{0,0,0,0,FPCSG00696,"PCSG00696"}},//choice
|
||||
//Tsuki ni Yorisou Otome no Sahou
|
||||
{0x8002aefa,{0,2,0,0,0,"PCSG00648"}},//dialogue,sjis
|
||||
//MARGINAL#4 IDOL OF SUPERNOVA
|
||||
{0x800718f8,{0,0,0,0,FPCSG00448,"PCSG00448"}},//dialogue,sjis
|
||||
//Nekketsu Inou Bukatsu-tan Trigger Kiss
|
||||
{0x8004e44a,{0,0,0,0,FPCSG00410,"PCSG00410"}},//dialogue,sjis
|
||||
//バイナリースター Binary Star
|
||||
{0x80058608,{0,1,0,0,FPCSG00389,"PCSG00389"}},//dialogue,sjis
|
||||
{0x80021292,{0,0,0,0,FPCSG00389,"PCSG00389"}},//name
|
||||
//Amagami
|
||||
{0x80070658,{0,0,0,TPCSG00291,0,"PCSG00291"}},
|
||||
//Rui wa Tomo o Yobu
|
||||
{0x81003db0,{CODEC_UTF8,1,0,0,FPCSG00839,"PCSG00216"}},//dialogue
|
||||
//Reine des Fleurs
|
||||
{0x8001bff2,{0,0,0,0,FPCSG00405,"PCSG00405"}},//dialogue,sjis
|
||||
//Muv-Luv
|
||||
{0x80118f10,{0,5,0,0,PCSG00776,"PCSG00776"}},//dialogue, choices
|
||||
{0x80126e7e,{0,0,0,0,PCSG00776,"PCSG00776"}},//dialogue
|
||||
//Re:Birthday Song ~Koi o Utau Shinigami~
|
||||
{0x80033af6,{0,0,2,0,0,"PCSG00911"}},//dialogue
|
||||
//Un:Birthday Song ~Ai o Utau Shinigami~
|
||||
{0x80038538,{0,0,0,PCSG00911,0,"PCSG00911"}},
|
||||
{0x80004b52,{0,3,5,0,0,"PCSG00911"}},
|
||||
address = results + 5;
|
||||
|
||||
};
|
||||
return 1;
|
||||
}();
|
||||
while (true)
|
||||
{
|
||||
std::string text = (char *)address;
|
||||
final_string += text;
|
||||
address = address + (text.size() + 1);
|
||||
|
||||
auto bytes = (BYTE *)address;
|
||||
|
||||
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF))
|
||||
break;
|
||||
address = address + (3);
|
||||
bytes = (BYTE *)address;
|
||||
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF))
|
||||
break;
|
||||
|
||||
address = address + (5);
|
||||
}
|
||||
write_string_new(data, len, final_string);
|
||||
}
|
||||
void TPCSG00291(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto a2 = VITA3K::emu_arg(stack)[0];
|
||||
|
||||
auto vm = *(DWORD *)(a2 + (0x28));
|
||||
vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
|
||||
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 8);
|
||||
uintptr_t address = VITA3K::emu_addr(stack, vm);
|
||||
auto len1 = *(DWORD *)(address + 4);
|
||||
auto p = address + 0x20;
|
||||
if (len1 > 4 && *(WORD *)(p + 2) == 0)
|
||||
{
|
||||
auto p1 = *(DWORD *)(address + 8);
|
||||
vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
|
||||
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC);
|
||||
p = VITA3K::emu_addr(stack, vm);
|
||||
}
|
||||
static int fm = 0;
|
||||
static std::string pre;
|
||||
auto b = fm;
|
||||
auto s = [](uintptr_t address)
|
||||
{
|
||||
auto frist = *(WORD *)address;
|
||||
auto lo = frist & 0xFF; // uppercase: 41->5A
|
||||
auto hi = frist >> 8;
|
||||
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
std::string s;
|
||||
int i = 0;
|
||||
WORD c;
|
||||
char buf[3] = {0};
|
||||
while ((c = *(WORD *)(address + i)) != 0)
|
||||
{
|
||||
// reverse endian: ShiftJIS BE => LE
|
||||
buf[0] = c >> 8;
|
||||
buf[1] = c & 0xFF;
|
||||
|
||||
if (c == 0x815e /* / */)
|
||||
{
|
||||
s += ' '; // single line
|
||||
}
|
||||
else if (buf[0] == 0)
|
||||
{
|
||||
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
|
||||
//// 4e00 6d00=>PLAYER
|
||||
// do nothing
|
||||
if (buf[1] == 0x4e)
|
||||
{
|
||||
s += "PLAYER";
|
||||
fm++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s += buf;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
return s;
|
||||
}(p);
|
||||
if (b > 0)
|
||||
{
|
||||
fm--;
|
||||
return;
|
||||
}
|
||||
if (s == pre)
|
||||
return;
|
||||
pre = s;
|
||||
write_string_new(data, len, s);
|
||||
}
|
||||
|
||||
bool FPCSG00468(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"(\\n\u3000*|\\k)"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(\[|\*[^\]]+])"), "");
|
||||
s = std::regex_replace(s, std::regex(u8"×"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00808(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"(^\s+|\s+$)"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(\s*(#n)*\s*)"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00855(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"(#n\u3000*)"), "");
|
||||
s = std::regex_replace(s, std::regex(R"(#\w.+?])"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
template <int idx>
|
||||
bool FPCSG00855_2(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
static std::string last;
|
||||
if (last == s)
|
||||
return false;
|
||||
last = s;
|
||||
strReplace(s, u8"Χ", u8"、");
|
||||
strReplace(s, u8"Δ", u8"。");
|
||||
strReplace(s, u8"Λ", u8"っ");
|
||||
strReplace(s, u8"《", u8"(");
|
||||
strReplace(s, u8"》", u8")");
|
||||
strReplace(s, u8"∫", u8"「");
|
||||
strReplace(s, u8"∨", u8"」");
|
||||
strReplace(s, u8"∴", u8"『");
|
||||
strReplace(s, u8"∵", u8"』");
|
||||
strReplace(s, u8"П", u8"【");
|
||||
strReplace(s, u8"Ц", u8"】");
|
||||
if (write_string_overwrite(data, len, s))
|
||||
return FPCSG00855(data, len, hp);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
bool FPCSG00477(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
auto ws = StringToWideString(s, 932).value();
|
||||
ws = std::regex_replace(ws, std::wregex(LR"(#n\u3000*)"), L"");
|
||||
ws = std::regex_replace(ws, std::wregex(LR"(#\w.+?])"), L"");
|
||||
s = WideStringToString(ws, 932);
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG00852(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
auto ws = StringToWideString(s, 932).value();
|
||||
ws = std::regex_replace(ws, std::wregex(LR"(\^)"), L"");
|
||||
s = WideStringToString(ws, 932);
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG01066(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
s = std::regex_replace(s, std::regex(R"(\n\u3000*)"), "");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
bool FPCSG01075(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
if (!FPCSG00808(data, len, hp))
|
||||
return false;
|
||||
auto s = std::string((char *)data, *len);
|
||||
static std::string last;
|
||||
if (last == s)
|
||||
return false;
|
||||
last = s;
|
||||
return true;
|
||||
}
|
||||
auto _ = []()
|
||||
{
|
||||
emfunctionhooks = {
|
||||
// Tsuihou Senkyo
|
||||
{0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis
|
||||
// 死神と少女 Shinigami to Shoujo
|
||||
{0x800204ba, {0, 2, 0, 0, FPCSG01282<0>, "PCSG01282"}}, // dialogueNVL,sjis
|
||||
{0x8000f00e, {0, 1, 0, 0, FPCSG01282<1>, "PCSG01282"}}, // dialogue main
|
||||
{0x80011f1a, {0, 0, 0, 0, FPCSG01282<2>, "PCSG01282"}}, // Name
|
||||
{0x8001ebac, {0, 1, 0, 0, FPCSG01282<3>, "PCSG01282"}}, // choices
|
||||
// 神凪ノ杜 Kannagi no Mori Satsukiame Tsuzuri
|
||||
{0x828bb50c, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // dialogue
|
||||
{0x828ba9b6, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // name
|
||||
{0x8060D376, {CODEC_UTF8, 0, 0, 0, 0, "PCSG01268"}}, // vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason.
|
||||
// Sanzen Sekai Yuugi ~MultiUniverse Myself~
|
||||
{0x8005ae24, {0, 0, 0, 0, 0, "PCSG01194"}}, // dialouge+name,sjis,need remap jis char,to complex
|
||||
// Marginal #4 Road to Galaxy
|
||||
{0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text
|
||||
// BLACK WOLVES SAGA -Weiβ und Schwarz-
|
||||
{0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text
|
||||
// New Game! The Challenge Stage!
|
||||
{0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}},
|
||||
// Kenka Banchou Otome
|
||||
{0x80009722, {CODEC_UTF16, 0, 0, 0, FPCSG00839, "PCSG00839"}},
|
||||
// Arcana famiglia -La storia della Arcana Famiglia-
|
||||
{0x80070e30, {0, 2, 0, 0, FPCSG00751, "PCSG00751"}}, // all,sjis
|
||||
{0x80070cdc, {0, 1, 0, 0, FPCSG00751, "PCSG00751"}}, // text
|
||||
// もし、この世界に神様がいるとするならば。 Moshi, Kono Sekai ni Kami-sama ga Iru to Suru Naraba.
|
||||
{0x80c1f270, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // dialogue
|
||||
{0x80d48bfc, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<1>, FPCSG00706, "PCSG00706"}}, // Dictionary1
|
||||
{0x80d48c20, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // Dictionary2
|
||||
// Angelique Retour
|
||||
{0x8008bd1a, {0, 1, 0, 0, FPCSG00696, "PCSG00696"}}, // text1,sjis
|
||||
{0x8008cd48, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // text2
|
||||
{0x8008f75a, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // choice
|
||||
// Tsuki ni Yorisou Otome no Sahou
|
||||
{0x8002aefa, {0, 2, 0, 0, 0, "PCSG00648"}}, // dialogue,sjis
|
||||
// MARGINAL#4 IDOL OF SUPERNOVA
|
||||
{0x800718f8, {0, 0, 0, 0, FPCSG00448, "PCSG00448"}}, // dialogue,sjis
|
||||
// Nekketsu Inou Bukatsu-tan Trigger Kiss
|
||||
{0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis
|
||||
// バイナリースター Binary Star
|
||||
{0x80058606, {0, 1, 0xd, 0, FPCSG00389, "PCSG00389"}}, // dialogue,sjis
|
||||
// Amagami
|
||||
{0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}},
|
||||
// Rui wa Tomo o Yobu
|
||||
{0x81003db0, {CODEC_UTF8, 1, 0, 0, FPCSG00839, "PCSG00216"}}, // dialogue
|
||||
// Reine des Fleurs
|
||||
{0x8001bff2, {0, 0, 0, 0, FPCSG00405, "PCSG00405"}}, // dialogue,sjis
|
||||
// Muv-Luv
|
||||
{0x80118f10, {0, 5, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue, choices
|
||||
{0x80126e7e, {0, 0, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue
|
||||
// Re:Birthday Song ~Koi o Utau Shinigami~
|
||||
{0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue
|
||||
// Un:Birthday Song ~Ai o Utau Shinigami~
|
||||
{0x80038538, {0, 0, 0, PCSG00912, 0, "PCSG00912"}},
|
||||
{0x80033d66, {0, 3, 4, 0, FPCSG00912, "PCSG00912"}},
|
||||
// Sora*yume
|
||||
{0x8000bad4, {0, 1, 0, 0, FPCSG00401, "PCSG00401"}},
|
||||
// Tengai ni Mau, Iki na Hana
|
||||
|
||||
{0x8006808e, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
|
||||
{0x80089408, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
|
||||
|
||||
// Kokuchou no Psychedelica (黒蝶のサイケデリカ)
|
||||
{0x80043538, {CODEC_UTF8, 1, 0, 0, FPCSG00468, "PCSG00468"}},
|
||||
// Haitaka no Psychedelica (灰鷹のサイケデリカ)
|
||||
{0x80022c06, {CODEC_UTF8, 4, 0, 0, FPCSG00468, "PCSG00812"}},
|
||||
// Yuukyuu no Tierblade -Lost Chronicle- (悠久のティアブレイド -Lost Chronicle-)
|
||||
{0x8003542a, {CODEC_UTF8, 10, 0, 0, FPCSG00808, "PCSG00808"}},
|
||||
{0x8002a95a, {CODEC_UTF8, 6, 0, 0, FPCSG00808, "PCSG00808"}},
|
||||
{0x801a98aa, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
|
||||
{0x801a42bc, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
|
||||
{0x801a42d0, {CODEC_UTF8, 7, 0, 0, FPCSG00808, "PCSG00808"}},
|
||||
// Yuukyuu no Tierblade -Fragments of Memory- (悠久のティアブレイド -Fragments of Memory-)
|
||||
{0x80035f44, {CODEC_UTF8, 10, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x8000d868, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x8004598e, {CODEC_UTF8, 0, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x801b1d16, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x801ac31e, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x801ac33a, {CODEC_UTF8, 7, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x801b879a, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
{0x8009f570, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
|
||||
// Magic Kyun! Renaissance (マジきゅんっ!ルネッサンス)
|
||||
{0x8008375a, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
|
||||
{0x8001c194, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
|
||||
// Chouchou Jiken Lovesodic / Chouchou Jiken Rhapsodic (蝶々事件ラブソディック)
|
||||
{0x8008dea2, {CODEC_UTF8, 4, 0, 0, FPCSG01066, "PCSG01066"}},
|
||||
{0x8008eb38, {CODEC_UTF8, 0, 0, 0, FPCSG01066, "PCSG01066"}},
|
||||
// Hyakka Yakou (百華夜光)
|
||||
{0x80032b30, {0, 8, 0, 0, 0, "PCSG00477"}},
|
||||
{0x80019c5a, {0, 5, 0, 0, 0, "PCSG00477"}},
|
||||
{0x80031a46, {0, 6, 0, 0, 0, "PCSG00477"}},
|
||||
{0x8003a49a, {0, 0, 0, 0, FPCSG00477, "PCSG00477"}},
|
||||
{0x80182532, {0, 7, 0, 0, FPCSG00477, "PCSG00477"}},
|
||||
{0x8017d1da, {0, 5, 0, 0, 0, "PCSG00477"}},
|
||||
{0x8017d478, {0, 4, 0, 0, 0, "PCSG00477"}},
|
||||
{0x8017a6aa, {0, 6, 0, 0, 0, "PCSG00477"}},
|
||||
// Hana Oboro ~Sengoku-den Ranki~ (花朧 ~戦国伝乱奇~)
|
||||
{0x80037600, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
|
||||
{0x80036580, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
|
||||
{0x801a2ada, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<0>, "PCSG00855"}},
|
||||
{0x801a2ba8, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<1>, "PCSG00855"}},
|
||||
{0x801a2d9e, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<2>, "PCSG00855"}},
|
||||
{0x801a2e68, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<3>, "PCSG00855"}},
|
||||
};
|
||||
return 1;
|
||||
}();
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
|
||||
|
||||
class vita3k:public ENGINE{
|
||||
public:
|
||||
vita3k(){
|
||||
|
||||
check_by=CHECK_BY::FILE;
|
||||
is_engine_certain=false;
|
||||
check_by_target=L"Vita3K.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
class vita3k : public ENGINE
|
||||
{
|
||||
public:
|
||||
vita3k()
|
||||
{
|
||||
|
||||
check_by = CHECK_BY::FILE;
|
||||
is_engine_certain = false;
|
||||
check_by_target = L"Vita3K.exe";
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
2904
LunaHook/engine64/yuzu.cpp
Normal file
2904
LunaHook/engine64/yuzu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
17
LunaHook/engine64/yuzu.h
Normal file
17
LunaHook/engine64/yuzu.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
class yuzu : public ENGINE
|
||||
{
|
||||
public:
|
||||
yuzu()
|
||||
{
|
||||
|
||||
is_engine_certain = false;
|
||||
check_by = CHECK_BY::CUSTOM;
|
||||
check_by_target = []()
|
||||
{
|
||||
return (wcscmp(processName_lower, L"suyu.exe") == 0 || wcscmp(processName_lower, L"yuzu.exe") == 0 || wcscmp(processName_lower, L"sudachi.exe") == 0);
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
||||
|
||||
|
||||
class yuzusuyu:public ENGINE{
|
||||
public:
|
||||
yuzusuyu(){
|
||||
|
||||
is_engine_certain=false;
|
||||
check_by=CHECK_BY::CUSTOM;
|
||||
check_by_target=[](){
|
||||
|
||||
return (wcscmp(processName_lower, L"suyu.exe")==0 || wcscmp(processName_lower, L"yuzu.exe")==0|| wcscmp(processName_lower, L"sudachi.exe")==0);
|
||||
};
|
||||
};
|
||||
bool attach_function();
|
||||
};
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "engine64/TYPEMOON.h"
|
||||
#include "engine64/Kincaid.h"
|
||||
#include "engine64/LightVN.h"
|
||||
#include "engine64/yuzusuyu.h"
|
||||
#include "engine64/yuzu.h"
|
||||
#include "engine64/Ryujinx.h"
|
||||
#include "engine64/vita3k.h"
|
||||
#include "engine64/rpcs3.h"
|
||||
@ -42,7 +42,7 @@ std::vector<ENGINE *> check_engines()
|
||||
new _5pb,
|
||||
new TYPEMOON,
|
||||
new ENTERGRAM,
|
||||
new yuzusuyu,
|
||||
new yuzu,
|
||||
new PPSSPPengine,
|
||||
new vita3k,
|
||||
new rpcs3,
|
||||
|
@ -1,329 +1,377 @@
|
||||
#include<queue>
|
||||
#include"emujitarg.hpp"
|
||||
#include <queue>
|
||||
#include "emujitarg.hpp"
|
||||
|
||||
namespace ppsspp{
|
||||
bool ULJS00403_filter(void* data, size_t* len, HookParam* hp){
|
||||
std::string result = std::string((char*)data,*len);
|
||||
std::regex newlinePattern(R"((\\n)+)");
|
||||
result = std::regex_replace(result, newlinePattern, " ");
|
||||
std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))");
|
||||
result = std::regex_replace(result, pattern, "");
|
||||
return write_string_overwrite(data,len,result);
|
||||
}
|
||||
|
||||
|
||||
void ULJS00339(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto a2= PPSSPP::emu_arg(stack)[0];
|
||||
|
||||
auto vm = *(DWORD*)(a2+(0x28));
|
||||
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
|
||||
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+8);
|
||||
uintptr_t address=PPSSPP::emu_addr(stack,vm);
|
||||
auto len1=*(DWORD*)(address+4);
|
||||
auto p=address+0x20;
|
||||
if(len1>4 && *(WORD*)(p+2)==0){
|
||||
auto p1=*(DWORD*)(address+8);
|
||||
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm);
|
||||
vm=*(DWORD*)PPSSPP::emu_addr(stack,vm+0xC);
|
||||
p=PPSSPP::emu_addr(stack,vm);
|
||||
namespace ppsspp
|
||||
{
|
||||
bool ULJS00403_filter(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
std::string result = std::string((char *)data, *len);
|
||||
std::regex newlinePattern(R"((\\n)+)");
|
||||
result = std::regex_replace(result, newlinePattern, " ");
|
||||
std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))");
|
||||
result = std::regex_replace(result, pattern, "");
|
||||
return write_string_overwrite(data, len, result);
|
||||
}
|
||||
static int fm=0;
|
||||
static std::string pre;
|
||||
auto b=fm;
|
||||
auto s=[](uintptr_t address){
|
||||
auto frist = *(WORD*)address;
|
||||
auto lo = frist & 0xFF; // uppercase: 41->5A
|
||||
auto hi = frist >> 8;
|
||||
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */) {
|
||||
return std::string();
|
||||
}
|
||||
std::string s ;int i = 0;WORD c;
|
||||
char buf[3]={0};
|
||||
while ((c = *(WORD*)(address+i)) != 0) {
|
||||
// reverse endian: ShiftJIS BE => LE
|
||||
buf[0] = c >> 8;
|
||||
buf[1] = c & 0xFF;
|
||||
|
||||
if (c == 0x815e /* / */) {
|
||||
s += ' '; // single line
|
||||
void ULJS00339(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto a2 = PPSSPP::emu_arg(stack)[0];
|
||||
|
||||
auto vm = *(DWORD *)(a2 + (0x28));
|
||||
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
|
||||
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 8);
|
||||
uintptr_t address = PPSSPP::emu_addr(stack, vm);
|
||||
auto len1 = *(DWORD *)(address + 4);
|
||||
auto p = address + 0x20;
|
||||
if (len1 > 4 && *(WORD *)(p + 2) == 0)
|
||||
{
|
||||
auto p1 = *(DWORD *)(address + 8);
|
||||
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
|
||||
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC);
|
||||
p = PPSSPP::emu_addr(stack, vm);
|
||||
}
|
||||
static int fm = 0;
|
||||
static std::string pre;
|
||||
auto b = fm;
|
||||
auto s = [](uintptr_t address)
|
||||
{
|
||||
auto frist = *(WORD *)address;
|
||||
auto lo = frist & 0xFF; // uppercase: 41->5A
|
||||
auto hi = frist >> 8;
|
||||
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
else if (buf[0] == 0) {
|
||||
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
|
||||
//// 4e00 6d00=>PLAYER
|
||||
// do nothing
|
||||
if (buf[1] == 0x4e) {
|
||||
s += "PLAYER";
|
||||
fm++;
|
||||
std::string s;
|
||||
int i = 0;
|
||||
WORD c;
|
||||
char buf[3] = {0};
|
||||
while ((c = *(WORD *)(address + i)) != 0)
|
||||
{
|
||||
// reverse endian: ShiftJIS BE => LE
|
||||
buf[0] = c >> 8;
|
||||
buf[1] = c & 0xFF;
|
||||
|
||||
if (c == 0x815e /* / */)
|
||||
{
|
||||
s += ' '; // single line
|
||||
}
|
||||
else if (buf[0] == 0)
|
||||
{
|
||||
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
|
||||
//// 4e00 6d00=>PLAYER
|
||||
// do nothing
|
||||
if (buf[1] == 0x4e)
|
||||
{
|
||||
s += "PLAYER";
|
||||
fm++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s += buf;
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
return s;
|
||||
}(p);
|
||||
if (b > 0)
|
||||
{
|
||||
fm--;
|
||||
return;
|
||||
}
|
||||
if (s == pre)
|
||||
return;
|
||||
pre = s;
|
||||
write_string_new(data, len, s);
|
||||
}
|
||||
|
||||
bool NPJH50909_filter(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
std::string result = std::string((char *)data, *len);
|
||||
auto ws = StringToWideString(result, 932).value();
|
||||
// Remove single line markers
|
||||
ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" ");
|
||||
|
||||
// Remove scale marker
|
||||
ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L"");
|
||||
|
||||
// Reformat name
|
||||
std::wsmatch match;
|
||||
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「")))
|
||||
{
|
||||
std::wstring name = match[1].str();
|
||||
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
|
||||
ws = name + L"\n" + ws;
|
||||
}
|
||||
return write_string_overwrite(data, len, WideStringToString(ws, 932));
|
||||
}
|
||||
|
||||
bool ULJM06119_filter(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
std::string s = std::string((char *)data, *len);
|
||||
|
||||
std::regex pattern(R"(/\[[^\]]+./g)");
|
||||
s = std::regex_replace(s, pattern, "");
|
||||
|
||||
std::regex tagPattern(R"(/\\k|\\x|%C|%B)");
|
||||
s = std::regex_replace(s, tagPattern, "");
|
||||
|
||||
std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)");
|
||||
s = std::regex_replace(s, colorPattern, "");
|
||||
|
||||
std::regex newlinePattern(R"(/\n+)");
|
||||
s = std::regex_replace(s, newlinePattern, " ");
|
||||
return write_string_overwrite(data, len, s);
|
||||
}
|
||||
|
||||
bool ULJM06036_filter(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
std::wstring result = std::wstring((wchar_t *)data, *len / 2);
|
||||
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
|
||||
result = std::regex_replace(result, pattern, L"$2");
|
||||
std::wregex tagPattern(LR"(<[A-Z]+>)");
|
||||
result = std::regex_replace(result, tagPattern, L"");
|
||||
return write_string_overwrite(data, len, result);
|
||||
}
|
||||
|
||||
namespace Corda
|
||||
{
|
||||
std::string readBinaryString(uintptr_t address, bool *haveName)
|
||||
{
|
||||
*haveName = false;
|
||||
if ((*(WORD *)address & 0xF0FF) == 0x801b)
|
||||
{
|
||||
*haveName = true;
|
||||
address = address + 2; // (1)
|
||||
}
|
||||
std::string s;
|
||||
int i = 0;
|
||||
uint8_t c;
|
||||
while ((c = *(uint8_t *)(address + i)) != 0)
|
||||
{
|
||||
if (c == 0x1b)
|
||||
{
|
||||
if (*haveName)
|
||||
return s; // (1) skip junk after name
|
||||
|
||||
c = *(uint8_t *)(address + (i + 1));
|
||||
if (c == 0x7f)
|
||||
i += 5;
|
||||
else
|
||||
i += 2;
|
||||
}
|
||||
else if (c == 0x0a)
|
||||
{
|
||||
s += '\n';
|
||||
i += 1;
|
||||
}
|
||||
else if (c == 0x20)
|
||||
{
|
||||
s += ' ';
|
||||
i += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i)));
|
||||
s += std::string((char *)(address + i), len);
|
||||
i += len; // encoder.encode(c).byteLength;
|
||||
}
|
||||
}
|
||||
else {
|
||||
s+=buf;
|
||||
}
|
||||
i += 2;
|
||||
return s;
|
||||
}
|
||||
return s;
|
||||
}(p);
|
||||
if(b>0){
|
||||
fm--;
|
||||
return;
|
||||
}
|
||||
if(s==pre)return ;
|
||||
pre=s;
|
||||
write_string_new(data,len,s);
|
||||
}
|
||||
|
||||
void ULJM05428(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
auto address = PPSSPP::emu_arg(stack)[1];
|
||||
bool haveNamve;
|
||||
auto s = Corda::readBinaryString(address, &haveNamve);
|
||||
*split = haveNamve;
|
||||
write_string_new(data, len, s);
|
||||
}
|
||||
|
||||
bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){
|
||||
std::string result = std::string((char*)data,*len);
|
||||
auto ws=StringToWideString(result,932).value();
|
||||
// Remove single line markers
|
||||
ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" ");
|
||||
|
||||
// Remove scale marker
|
||||
ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L"");
|
||||
|
||||
// Reformat name
|
||||
std::wsmatch match;
|
||||
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) {
|
||||
std::wstring name = match[1].str();
|
||||
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
|
||||
ws = name + L"\n" + ws;
|
||||
}
|
||||
return write_string_overwrite(data,len,WideStringToString(ws,932));
|
||||
}
|
||||
|
||||
bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){
|
||||
std::string s = std::string((char*)data,*len);
|
||||
|
||||
std::regex pattern(R"(/\[[^\]]+./g)");
|
||||
s = std::regex_replace(s, pattern, "");
|
||||
|
||||
std::regex tagPattern(R"(/\\k|\\x|%C|%B)");
|
||||
s = std::regex_replace(s, tagPattern, "");
|
||||
|
||||
std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)");
|
||||
s = std::regex_replace(s, colorPattern, "");
|
||||
|
||||
std::regex newlinePattern(R"(/\n+)");
|
||||
s = std::regex_replace(s, newlinePattern, " ");
|
||||
return write_string_overwrite(data,len,s);
|
||||
}
|
||||
|
||||
bool ULJM06036_filter(void* data, size_t* len, HookParam* hp){
|
||||
std::wstring result = std::wstring((wchar_t*)data,*len/2);
|
||||
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
|
||||
result = std::regex_replace(result, pattern, L"$2");
|
||||
std::wregex tagPattern(LR"(<[A-Z]+>)");
|
||||
result = std::regex_replace(result, tagPattern, L"");
|
||||
return write_string_overwrite(data,len,result);
|
||||
}
|
||||
|
||||
namespace Corda{
|
||||
std::string readBinaryString(uintptr_t address,bool* haveName){
|
||||
* haveName=false;
|
||||
if ((*(WORD*)address & 0xF0FF) == 0x801b) {
|
||||
*haveName = true;
|
||||
address = address+2; // (1)
|
||||
}
|
||||
std::string s;int i=0;uint8_t c;
|
||||
while ((c = *(uint8_t*)(address+i)) != 0) {
|
||||
if (c == 0x1b) {
|
||||
if (*haveName)
|
||||
return s; // (1) skip junk after name
|
||||
|
||||
c = *(uint8_t*)(address+(i + 1));
|
||||
if (c == 0x7f)
|
||||
i += 5;
|
||||
else
|
||||
i += 2;
|
||||
}
|
||||
else if (c == 0x0a) {
|
||||
s += '\n';
|
||||
i += 1;
|
||||
}
|
||||
else if (c == 0x20) {
|
||||
s += ' ';
|
||||
i += 1;
|
||||
}
|
||||
else {
|
||||
auto len=1+(IsDBCSLeadByteEx(932,*(BYTE*)(address+i)));
|
||||
s += std::string((char*)(address+i),len);
|
||||
i += len;//encoder.encode(c).byteLength;
|
||||
}
|
||||
void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
if (hp->emu_addr != 0x886162c)
|
||||
{
|
||||
auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c;
|
||||
*data = addr;
|
||||
*len = strlen((char *)addr);
|
||||
return;
|
||||
}
|
||||
return s;
|
||||
auto address = PPSSPP::emu_arg(stack)[1];
|
||||
bool haveNamve;
|
||||
auto s = Corda::readBinaryString(address, &haveNamve);
|
||||
*split = haveNamve;
|
||||
write_string_new(data, len, s);
|
||||
}
|
||||
}
|
||||
|
||||
void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address= PPSSPP::emu_arg(stack)[1];
|
||||
bool haveNamve;
|
||||
auto s=Corda::readBinaryString(address,&haveNamve);
|
||||
*split=haveNamve;
|
||||
write_string_new(data,len,s);
|
||||
}
|
||||
bool ULJM05943F(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
std::regex pattern1("#n+");
|
||||
std::string replacement1 = " ";
|
||||
std::string result1 = std::regex_replace(s, pattern1, replacement1);
|
||||
std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
|
||||
return write_string_overwrite(data, len, result2);
|
||||
}
|
||||
|
||||
void ULJM05054(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
if (hp->emu_addr != 0x886162c) {
|
||||
auto addr=PPSSPP::emu_arg(stack)[0]+0x3c;
|
||||
*data=addr;*len=strlen((char*)addr);
|
||||
return;
|
||||
}
|
||||
auto address= PPSSPP::emu_arg(stack)[1];
|
||||
bool haveNamve;
|
||||
auto s=Corda::readBinaryString(address,&haveNamve);
|
||||
*split=haveNamve;
|
||||
write_string_new(data,len,s);
|
||||
}
|
||||
bool FULJM05603(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
|
||||
StringCharReplacer(text, len, "%N", 2, ' ');
|
||||
StringFilter(text, len, "%K", 2);
|
||||
StringFilter(text, len, "%P", 2);
|
||||
|
||||
bool ULJM05943F(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
std::regex pattern1("#n+");
|
||||
std::string replacement1 = " ";
|
||||
std::string result1 = std::regex_replace(s, pattern1, replacement1);
|
||||
std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
|
||||
return write_string_overwrite(data,len,result2);
|
||||
}
|
||||
|
||||
bool FULJM05603(LPVOID data, size_t* size, HookParam*)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t*>(size);
|
||||
|
||||
StringCharReplacer(text, len, "%N", 2, ' ');
|
||||
StringFilter(text, len, "%K", 2);
|
||||
StringFilter(text, len, "%P", 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
namespace NPJH50530{
|
||||
std::string current;
|
||||
bool T(LPVOID data, size_t* size, HookParam*)
|
||||
{
|
||||
current=std::string((char*)data,*size);
|
||||
return true;
|
||||
}
|
||||
bool N(LPVOID data, size_t* size, HookParam*)
|
||||
{
|
||||
auto current1=std::string((char*)data,*size);
|
||||
return current!=current1;
|
||||
}
|
||||
}
|
||||
bool FULJM05889(LPVOID data, size_t* size, HookParam*)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t*>(size);
|
||||
for(size_t i=0;i<*len;){
|
||||
if(IsDBCSLeadByteEx(932,(text[i]))){
|
||||
i+=2;
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
namespace NPJH50530
|
||||
{
|
||||
std::string current;
|
||||
bool T(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
current = std::string((char *)data, *size);
|
||||
return true;
|
||||
}
|
||||
bool N(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto current1 = std::string((char *)data, *size);
|
||||
return current != current1;
|
||||
}
|
||||
if(text[i]=='^')
|
||||
text[i]='\n';
|
||||
|
||||
i+=1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool FNPJH50243(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto s = std::wstring((wchar_t *)data, *size / 2);
|
||||
s = std::regex_replace(s, std::wregex(LR"(<(.*?)\|(.*?)>)"), L"$1");
|
||||
return write_string_overwrite(data, size, s);
|
||||
}
|
||||
bool FULJM05889(LPVOID data, size_t *size, HookParam *)
|
||||
{
|
||||
auto text = reinterpret_cast<LPSTR>(data);
|
||||
auto len = reinterpret_cast<size_t *>(size);
|
||||
for (size_t i = 0; i < *len;)
|
||||
{
|
||||
if (IsDBCSLeadByteEx(932, (text[i])))
|
||||
{
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
if (text[i] == '^')
|
||||
text[i] = '\n';
|
||||
|
||||
bool NPJH50619F(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
std::regex pattern1("[\\r\\n]+");
|
||||
std::string replacement1 = "";
|
||||
std::string result1 = std::regex_replace(s, pattern1, replacement1);
|
||||
std::regex pattern2("^(.*?)\\)+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
|
||||
std::regex pattern3("#ECL+");
|
||||
std::string replacement3 = "";
|
||||
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
|
||||
std::regex pattern4("(#.+?\\))+");
|
||||
std::string replacement4 = "";
|
||||
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
|
||||
return write_string_overwrite(data,len,result4);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NPJH50619F(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
std::regex pattern1("[\\r\\n]+");
|
||||
std::string replacement1 = "";
|
||||
std::string result1 = std::regex_replace(s, pattern1, replacement1);
|
||||
std::regex pattern2("^(.*?)\\)+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
|
||||
std::regex pattern3("#ECL+");
|
||||
std::string replacement3 = "";
|
||||
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
|
||||
std::regex pattern4("(#.+?\\))+");
|
||||
std::string replacement4 = "";
|
||||
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
|
||||
return write_string_overwrite(data, len, result4);
|
||||
}
|
||||
|
||||
bool NPJH50505F(void* data, size_t* len, HookParam* hp){
|
||||
auto s = std::string((char*)data,*len);
|
||||
|
||||
std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(s, pattern2, replacement2);
|
||||
bool NPJH50505F(void *data, size_t *len, HookParam *hp)
|
||||
{
|
||||
auto s = std::string((char *)data, *len);
|
||||
|
||||
std::regex pattern3("#FAMILY");
|
||||
std::string replacement3 = "$FAMILY";
|
||||
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
|
||||
std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
|
||||
std::string replacement2 = "";
|
||||
std::string result2 = std::regex_replace(s, pattern2, replacement2);
|
||||
|
||||
std::regex pattern4("#GIVE");
|
||||
std::string replacement4 = "$GIVE";
|
||||
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
|
||||
std::regex pattern3("#FAMILY");
|
||||
std::string replacement3 = "$FAMILY";
|
||||
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
|
||||
|
||||
std::regex pattern5("(#[A-Z0-9\\-]+)+");
|
||||
std::string replacement5 = "";
|
||||
std::string result5 = std::regex_replace(result4, pattern5, replacement5);
|
||||
std::regex pattern4("#GIVE");
|
||||
std::string replacement4 = "$GIVE";
|
||||
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
|
||||
|
||||
std::regex pattern6("\\n+");
|
||||
std::string replacement6 = " ";
|
||||
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
|
||||
std::regex pattern5("(#[A-Z0-9\\-]+)+");
|
||||
std::string replacement5 = "";
|
||||
std::string result5 = std::regex_replace(result4, pattern5, replacement5);
|
||||
|
||||
return write_string_overwrite(data,len,result6);
|
||||
}
|
||||
std::regex pattern6("\\n+");
|
||||
std::string replacement6 = " ";
|
||||
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
|
||||
|
||||
return write_string_overwrite(data, len, result6);
|
||||
}
|
||||
|
||||
void QNPJH50909(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
|
||||
{
|
||||
uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110);
|
||||
*data = addr + 0x20;
|
||||
*len = *(DWORD *)(addr + 0x14) * 2;
|
||||
|
||||
if (0x6e87 == *(WORD *)*data)
|
||||
*len = 0;
|
||||
if (0x000a == *(WORD *)*data)
|
||||
*len = 0;
|
||||
}
|
||||
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks = {
|
||||
// Shinigami to Shoujo
|
||||
{0x883bf34, {0, 1, 0, 0, ULJS00403_filter, "ULJS00403"}},
|
||||
// Amagami
|
||||
{0x0886775c, {0, 0, 0, ULJS00339, 0, "ULJS00339"}}, // String.length()
|
||||
// Sekai de Ichiban Dame na Koi
|
||||
{0x8814adc, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // name + dialouge
|
||||
{0x8850b2c, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // onscreen toast
|
||||
// Dunamis15
|
||||
{0x0891D72C, {CODEC_UTF8, 0, 0, 0, ULJM06119_filter, "ULJM06119"}},
|
||||
// Princess Evangile Portable
|
||||
{0x88506d0, {CODEC_UTF16, 2, 0, 0, ULJM06036_filter, "ULJM06036"}}, // [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
|
||||
// Kin'iro no Corda 2f
|
||||
{0x89b59dc, {0, 0, 0, ULJM05428, 0, "ULJM05428"}},
|
||||
// Kin'iro no Corda
|
||||
{0x886162c, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
|
||||
{0x8899e90, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
|
||||
// Sol Trigger
|
||||
{0x8952cfc, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // dialog
|
||||
{0x884aad4, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // description
|
||||
{0x882e1b0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // system
|
||||
{0x88bb108, {CODEC_UTF8, 2, 0, 0, NPJH50619F, "NPJH50619"}}, // battle tutorial
|
||||
{0x89526a0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // battle info
|
||||
{0x88bcef8, {CODEC_UTF8, 1, 0, 0, NPJH50619F, "NPJH50619"}}, // battle talk
|
||||
// Fate/EXTRA CCC
|
||||
{0x8958490, {0, 0, 0, 0, NPJH50505F, "NPJH50505"}},
|
||||
// Kamigami no Asobi InFinite
|
||||
{0x088630f8, {0, 0, 0, QNPJH50909, 0, "NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
|
||||
{0x0887813c, {0, 3, 4, 0, 0, "NPJH50909"}}, // Question YN
|
||||
// Gekka Ryouran Romance
|
||||
{0x88eeba4, {0, 0, 0, 0, ULJM05943F, "ULJM05943"}}, // a0 - monologue text
|
||||
{0x8875e0c, {0, 1, 6, 0, ULJM05943F, "ULJM05943"}}, // a1 - dialogue text
|
||||
// My Merry May with be
|
||||
{0x886F014, {0, 3, 0, 0, FULJM05603, "ULJM05603"}},
|
||||
// Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition
|
||||
{0x88517C8, {0, 1, 0, 0, FULJM05603, "ULJM06114"}},
|
||||
// Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE
|
||||
{0x881c444, {FULL_STRING, 0, 0, 0, 0, "ULJM06321"}}, // name+text,sjit,FULL_STRING to split name and text
|
||||
// ましろ色シンフォニー *mutsu-no-hana
|
||||
{0x8868AB8, {0, 0, 0, 0, FULJM05889, "ULJM05889"}},
|
||||
// シャイニング・ブレイド
|
||||
{0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only
|
||||
{0x884DB44, {0, 1, 0, 0, NPJH50530::N, "NPJH50530"}}, // text+name
|
||||
// ティアーズ・トゥ・ティアラ 外伝 アヴァロンの謎 PORTABLE
|
||||
{0x890A4BC, {CODEC_UTF16, 1, 0, 0, FNPJH50243, "NPJH50243"}},
|
||||
// 薔薇ノ木ニ薔薇ノ花咲ク
|
||||
{0x881E560, {0, 1, 0, 0, 0, "ULJM05802"}},
|
||||
};
|
||||
|
||||
void QNPJH50909(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
uintptr_t addr = PPSSPP::emu_addr(stack,0x08975110);
|
||||
*data=addr+0x20;
|
||||
*len=*(DWORD*)(addr+0x14)*2;
|
||||
|
||||
if(0x6e87==*(WORD*)*data)*len=0;
|
||||
if(0x000a==*(WORD*)*data)*len=0;
|
||||
}
|
||||
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks= {
|
||||
//Shinigami to Shoujo
|
||||
{0x883bf34,{0,1,0,0,ULJS00403_filter,"ULJS00403"}},
|
||||
//Amagami
|
||||
{0x0886775c,{0,0,0,ULJS00339,0,"ULJS00339"}},// String.length()
|
||||
//Sekai de Ichiban Dame na Koi
|
||||
{0x8814adc,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// name + dialouge
|
||||
{0x8850b2c,{0,0,0,0,NPJH50909_filter,"ULJM05878"}},// onscreen toast
|
||||
//Dunamis15
|
||||
{0x0891D72C,{CODEC_UTF8,0,0,0,ULJM06119_filter,"ULJM06119"}},
|
||||
//Princess Evangile Portable
|
||||
{0x88506d0,{CODEC_UTF16,2,0,0,ULJM06036_filter,"ULJM06036"}},// [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
|
||||
//Kin'iro no Corda 2f
|
||||
{0x89b59dc,{0,0,0,ULJM05428,0,"ULJM05428"}},
|
||||
//Kin'iro no Corda
|
||||
{0x886162c,{0,0,0,ULJM05054,0,"ULJM05054"}},// dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
|
||||
{0x8899e90,{0,0,0,ULJM05054,0,"ULJM05054"}},// name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
|
||||
//Sol Trigger
|
||||
{0x8952cfc,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//dialog
|
||||
{0x884aad4,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//description
|
||||
{0x882e1b0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//system
|
||||
{0x88bb108,{CODEC_UTF8,2,0,0,NPJH50619F,"NPJH50619"}},//battle tutorial
|
||||
{0x89526a0,{CODEC_UTF8,0,0,0,NPJH50619F,"NPJH50619"}},//battle info
|
||||
{0x88bcef8,{CODEC_UTF8,1,0,0,NPJH50619F,"NPJH50619"}},//battle talk
|
||||
//Fate/EXTRA CCC
|
||||
{0x8958490,{0,0,0,0,NPJH50505F,"NPJH50505"}},
|
||||
//Kamigami no Asobi InFinite
|
||||
{0x088630f8,{0,0,0,QNPJH50909,0,"NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
|
||||
{0x0887813c,{0,3,4,0,0,"NPJH50909"}}, // Question YN
|
||||
//Gekka Ryouran Romance
|
||||
{0x88eeba4,{0,0,0,0,ULJM05943F,"ULJM05943"}},// a0 - monologue text
|
||||
{0x8875e0c,{0,1,6,0,ULJM05943F,"ULJM05943"}},// a1 - dialogue text
|
||||
//My Merry May with be
|
||||
{0x886F014,{0,3,0,0,FULJM05603,"ULJM05603"}},
|
||||
//Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition
|
||||
{0x88517C8,{0,1,0,0,FULJM05603,"ULJM06114"}},
|
||||
//Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE
|
||||
{0x881c444,{FULL_STRING,0,0,0,0,"ULJM06321"}},//name+text,sjit,FULL_STRING to split name and text
|
||||
//ましろ色シンフォニー *mutsu-no-hana
|
||||
{0x8868AB8,{0,0,0,0,FULJM05889,"ULJM05889"}},
|
||||
//シャイニング・ブレイド
|
||||
{0x8AA3B70,{0,0xC,0,0,NPJH50530::T,"NPJH50530"}},//text only
|
||||
{0x884DB44,{0,1,0,0,NPJH50530::N,"NPJH50530"}},//text+name
|
||||
};
|
||||
|
||||
}
|
@ -222,7 +222,6 @@ void SafeSendJitVeh(hook_stack *stack, uintptr_t address, uintptr_t em_addr, JIT
|
||||
}
|
||||
}
|
||||
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)
|
||||
@ -295,7 +294,7 @@ void SearchForHooks_Return()
|
||||
if (!records[i].em_addr)
|
||||
continue;
|
||||
hp.emu_addr = records[i].em_addr;
|
||||
hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT;
|
||||
hp.type = CODEC_UTF16 | USING_STRING | BREAK_POINT | NO_CONTEXT;
|
||||
hp.argidx = records[i].argidx;
|
||||
}
|
||||
NotifyHookFound(hp, (wchar_t *)records[i].text);
|
||||
|
@ -101,6 +101,15 @@ void ConsoleOutput(LPCSTR text, ...)
|
||||
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
|
||||
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Synchronized<std::unordered_map<uintptr_t, std::wstring>> modulecache;
|
||||
std::wstring &querymodule(uintptr_t addr)
|
||||
{
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T(*buffer), int len);
|
||||
void ConsoleOutput(LPCSTR text, ...);
|
||||
void WarningOutput(LPCSTR text, ...);
|
||||
void NotifyHookFound(HookParam hp, wchar_t *text);
|
||||
void NotifyHookRemove(uint64_t addr, LPCSTR name);
|
||||
bool NewHook(HookParam hp, LPCSTR name);
|
||||
@ -27,6 +28,6 @@ void context_set(hook_stack *, PCONTEXT);
|
||||
inline std::map<uintptr_t, std::pair<std::string, HookParam>> delayinserthook;
|
||||
void delayinsertadd(HookParam, std::string);
|
||||
void delayinsertNewHook(uintptr_t);
|
||||
|
||||
inline bool safeautoleaveveh = false;
|
||||
inline bool dont_detach = false;
|
||||
inline bool host_connected = false;
|
@ -127,7 +127,13 @@ bool TextHook::Insert(HookParam hp)
|
||||
if (hp.type & DIRECT_READ)
|
||||
return InsertReadCode();
|
||||
if (hp.type & BREAK_POINT)
|
||||
return InsertBreakPoint();
|
||||
{
|
||||
if (InsertBreakPoint())
|
||||
return true;
|
||||
if (safeautoleaveveh)
|
||||
return InsertBreakPoint(); // 搜索特殊码后,不会释放,导致virtualprotect查询失败,重试。
|
||||
return false;
|
||||
}
|
||||
return InsertHookCode();
|
||||
}
|
||||
uintptr_t win64find0000(uintptr_t addr)
|
||||
|
@ -292,12 +292,16 @@ LunaHost::LunaHost()
|
||||
hooksearchwindow->show();
|
||||
};
|
||||
|
||||
Host::Start(
|
||||
Host::StartEx(
|
||||
std::bind(&LunaHost::on_proc_connect, this, std::placeholders::_1),
|
||||
std::bind(&LunaHost::on_proc_disconnect, this, std::placeholders::_1),
|
||||
std::bind(&LunaHost::on_thread_create, this, std::placeholders::_1),
|
||||
std::bind(&LunaHost::on_thread_delete, this, std::placeholders::_1),
|
||||
std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2));
|
||||
std::bind(&LunaHost::on_text_recv, this, std::placeholders::_1, std::placeholders::_2),
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
std::bind(&LunaHost::on_warning, this, std::placeholders::_1));
|
||||
|
||||
mainlayout = new gridlayout();
|
||||
mainlayout->addcontrol(g_selectprocessbutton, 0, 0);
|
||||
@ -448,6 +452,10 @@ bool LunaHost::on_text_recv(TextThread &thread, std::wstring &output)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void LunaHost::on_warning(const std::wstring &warning)
|
||||
{
|
||||
MessageBoxW(winId, warning.c_str(), L"warning", 0);
|
||||
}
|
||||
void LunaHost::on_thread_create(TextThread &thread)
|
||||
{
|
||||
wchar_t buff[65535];
|
||||
|
@ -116,6 +116,7 @@ class LunaHost : public mainwindow
|
||||
void on_thread_delete(TextThread &thread);
|
||||
void on_proc_connect(DWORD pid);
|
||||
void on_proc_disconnect(DWORD pid);
|
||||
void on_warning(const std::wstring &);
|
||||
|
||||
void showtext(const std::wstring &text, bool clear);
|
||||
void updatelisttext(const std::wstring &text, LONG_PTR data);
|
||||
|
@ -464,7 +464,7 @@ std::array<InfoForExtension, 20> Pluginmanager::GetSentenceInfo(TextThread &thre
|
||||
static DWORD SelectedProcessId;
|
||||
auto currthread = (TextThread *)host->currentselect;
|
||||
SelectedProcessId = (currthread != 0) ? currthread->tp.processId : 0;
|
||||
DWORD (*GetSelectedProcessId)
|
||||
DWORD(*GetSelectedProcessId)
|
||||
() = []
|
||||
{ return SelectedProcessId; };
|
||||
|
||||
|
@ -35,7 +35,7 @@ struct plugindata
|
||||
VisSetting_t VisSetting;
|
||||
HMODULE hmodule;
|
||||
void clear();
|
||||
plugindata(){};
|
||||
plugindata() {};
|
||||
plugindata(const std::wstring &, Pluginmanager *, bool, HMODULE);
|
||||
bool valid();
|
||||
void initstatus(const pluginitem &);
|
||||
|
@ -2,15 +2,14 @@
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
_setmode(_fileno(stdout), _O_U16TEXT);
|
||||
_setmode(_fileno(stdin), _O_U16TEXT);
|
||||
wprintf_s(L"Usage: {'attach'|'detach'|hookcode} -Pprocessid\n");
|
||||
fflush(stdout);
|
||||
Host::Start([](auto) {}, [](auto) {}, [](auto&) {}, [](auto&) {}, [](TextThread& thread, std::wstring& output)
|
||||
{
|
||||
Host::Start([](auto) {}, [](auto) {}, [](auto &) {}, [](auto &) {}, [](TextThread &thread, std::wstring &output)
|
||||
{
|
||||
wprintf_s(L"[%I64X:%I32X:%I64X:%I64X:%I64X:%s:%s] %s\n",
|
||||
thread.handle,
|
||||
thread.tp.processId,
|
||||
@ -22,53 +21,67 @@ int main()
|
||||
output.c_str()
|
||||
);
|
||||
fflush(stdout);
|
||||
return false;
|
||||
});
|
||||
return false; });
|
||||
wchar_t input[500] = {};
|
||||
SearchParam sp = {};
|
||||
sp.codepage = Host::defaultCodepage;
|
||||
sp.length = 0;
|
||||
while (fgetws(input, 500, stdin))
|
||||
{
|
||||
if(wcslen(input)<=1)continue;//\r\n,第二行会直接只有一个\n
|
||||
if (wcslen(input) <= 1)
|
||||
continue; //\r\n,第二行会直接只有一个\n
|
||||
wchar_t command[500] = {};
|
||||
DWORD processId = 0;
|
||||
|
||||
int split;
|
||||
for (split = wcslen(input) - 1; split >= 1; split--) {
|
||||
if (input[split] == L'P' && input[split-1]=='-') {
|
||||
for (split = wcslen(input) - 1; split >= 1; split--)
|
||||
{
|
||||
if (input[split] == L'P' && input[split - 1] == '-')
|
||||
{
|
||||
processId = _wtoi(input + split + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (split == 1)continue;// ExitProcess(0);
|
||||
if (split == 1)
|
||||
continue; // ExitProcess(0);
|
||||
split -= 2;
|
||||
while (split > 0 && input[split] == L' ')split -= 1;
|
||||
if (split == 0)continue;//ExitProcess(0);
|
||||
while (split > 0 && input[split] == L' ')
|
||||
split -= 1;
|
||||
if (split == 0)
|
||||
continue; // ExitProcess(0);
|
||||
input[split + 1] = 0;
|
||||
wcscpy(command, input);
|
||||
//if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
|
||||
if (_wcsicmp(command, L"attach") == 0) Host::InjectProcess(processId);
|
||||
else if (_wcsicmp(command, L"detach") == 0) { Host::DetachProcess(processId); }
|
||||
else if (_wcsicmp(command, L"find") == 0) {
|
||||
// if (swscanf(input, L"%500s -P%d", command, &processId) != 2) ExitProcess(0);
|
||||
if (_wcsicmp(command, L"attach") == 0)
|
||||
Host::InjectProcess(processId);
|
||||
else if (_wcsicmp(command, L"detach") == 0)
|
||||
{
|
||||
Host::DetachProcess(processId);
|
||||
}
|
||||
else if (_wcsicmp(command, L"find") == 0)
|
||||
{
|
||||
std::shared_ptr<std::vector<std::wstring>> hooks = std::make_shared<std::vector<std::wstring>>();
|
||||
|
||||
try
|
||||
{
|
||||
Host::FindHooks(processId, sp,
|
||||
[hooks](HookParam hp, std::wstring text) {
|
||||
//if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) {
|
||||
if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) {
|
||||
hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n");
|
||||
[hooks](HookParam hp, std::wstring text)
|
||||
{
|
||||
// if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]"))) {
|
||||
if (std::regex_search(text, std::wregex(L"[\u3000-\ua000]")))
|
||||
{
|
||||
hooks->push_back(std::wstring(hp.hookcode) + L"=>" + text + L"\n");
|
||||
|
||||
|
||||
// *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text));
|
||||
}
|
||||
});
|
||||
// *hooks << sanitize(S(HookCode::Generate(hp) + L" => " + text));
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (wchar_t c)
|
||||
{
|
||||
std::wcout << c;
|
||||
}
|
||||
catch (wchar_t c) { std::wcout << c; }
|
||||
std::thread([hooks]
|
||||
{
|
||||
{
|
||||
for (int lastSize = 0; hooks->size() == 0 || hooks->size() != lastSize; Sleep(2000)) lastSize = hooks->size();
|
||||
|
||||
FILE* out = fopen("hook.txt", "a+,ccs=UTF-8");
|
||||
@ -76,34 +89,40 @@ int main()
|
||||
|
||||
fwrite(hook.c_str(), wcslen(hook.c_str()) * sizeof(wchar_t), 1, out);
|
||||
}
|
||||
fclose(out);
|
||||
}).detach();
|
||||
|
||||
fclose(out); })
|
||||
.detach();
|
||||
}
|
||||
|
||||
else {
|
||||
if (command[0] == L'-') {
|
||||
else
|
||||
{
|
||||
if (command[0] == L'-')
|
||||
{
|
||||
try
|
||||
{
|
||||
unsigned long long address;
|
||||
swscanf_s(command, L"-%llu", &address);
|
||||
Host::RemoveHook(processId, address);
|
||||
|
||||
}
|
||||
catch (std::out_of_range) {}
|
||||
catch (std::out_of_range)
|
||||
{
|
||||
}
|
||||
}
|
||||
else if (command[0] == L'=') {
|
||||
else if (command[0] == L'=')
|
||||
{
|
||||
int codepage;
|
||||
swscanf_s(command, L"=%d", &codepage);
|
||||
Host::defaultCodepage = codepage;
|
||||
}
|
||||
else if (command[0] == L'+') {
|
||||
else if (command[0] == L'+')
|
||||
{
|
||||
int flushDelay;
|
||||
swscanf_s(command, L"+%d", &flushDelay);
|
||||
TextThread::flushDelay = flushDelay;
|
||||
}
|
||||
else if (auto hp = HookCode::Parse(command)) Host::InsertHook(processId, hp.value());
|
||||
else ExitProcess(0);
|
||||
else if (auto hp = HookCode::Parse(command))
|
||||
Host::InsertHook(processId, hp.value());
|
||||
else
|
||||
ExitProcess(0);
|
||||
}
|
||||
}
|
||||
ExitProcess(0);
|
||||
|
@ -26,7 +26,7 @@ typedef void (*EmbedCallback)(const wchar_t *, ThreadParam);
|
||||
wchar_t hookcode[HOOKCODE_LEN]; \
|
||||
wcscpy_s(hookcode, HOOKCODE_LEN, thread.hp.hookcode); \
|
||||
strcpy_s(name, HOOK_NAME_SIZE, thread.hp.name);
|
||||
C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed)
|
||||
C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, ThreadEvent Create, ThreadEvent Destroy, OutputCallback Output, ConsoleHandler console, HookInsertHandler hookinsert, EmbedCallback embed, ConsoleHandler Warning)
|
||||
{
|
||||
Host::StartEx(
|
||||
Connect,
|
||||
@ -56,6 +56,10 @@ C_LUNA_API void Luna_Start(ProcessEvent Connect, ProcessEvent Disconnect, Thread
|
||||
[=](const std::wstring &output, const ThreadParam &tp)
|
||||
{
|
||||
embed(output.c_str(), tp);
|
||||
},
|
||||
[=](const std::wstring &output)
|
||||
{
|
||||
Warning(output.c_str());
|
||||
});
|
||||
}
|
||||
C_LUNA_API void Luna_Inject(DWORD pid, LPCWSTR basepath)
|
||||
|
@ -1,20 +1,19 @@
|
||||
#include "host.h"
|
||||
typedef LONG NTSTATUS;
|
||||
#include"yapi.hpp"
|
||||
#include"Lang/Lang.h"
|
||||
#include "yapi.hpp"
|
||||
#include "Lang/Lang.h"
|
||||
namespace
|
||||
{
|
||||
class ProcessRecord
|
||||
{
|
||||
public:
|
||||
ProcessRecord(DWORD processId, HANDLE pipe) :
|
||||
pipe(pipe),
|
||||
mappedFile2(OpenFileMappingW(FILE_MAP_READ|FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())),
|
||||
viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId))
|
||||
|
||||
{
|
||||
embedsharedmem=(EmbedSharedMem*)MapViewOfFile(mappedFile2, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
|
||||
//放到构造表里就不行,不知道为何。
|
||||
ProcessRecord(DWORD processId, HANDLE pipe) : pipe(pipe),
|
||||
mappedFile2(OpenFileMappingW(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, (EMBED_SHARED_MEM + std::to_wstring(processId)).c_str())),
|
||||
viewMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId))
|
||||
|
||||
{
|
||||
embedsharedmem = (EmbedSharedMem *)MapViewOfFile(mappedFile2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
|
||||
// 放到构造表里就不行,不知道为何。
|
||||
}
|
||||
|
||||
~ProcessRecord()
|
||||
@ -27,18 +26,17 @@ namespace
|
||||
{
|
||||
static_assert(sizeof(data) < PIPE_BUFFER_SIZE);
|
||||
std::thread([=]
|
||||
{
|
||||
WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr);
|
||||
}).detach();
|
||||
{ WriteFile(pipe, &data, sizeof(data), DUMMY, nullptr); })
|
||||
.detach();
|
||||
}
|
||||
|
||||
Host::HookEventHandler OnHookFound = [](HookParam hp, std::wstring text)
|
||||
{
|
||||
Host::AddConsoleOutput(std::wstring(hp.hookcode) + L": " + text);
|
||||
};
|
||||
|
||||
|
||||
|
||||
EmbedSharedMem *embedsharedmem;
|
||||
|
||||
private:
|
||||
HANDLE pipe;
|
||||
AutoHandle<> mappedFile2;
|
||||
@ -51,13 +49,16 @@ namespace
|
||||
|
||||
Host::ProcessEventHandler OnConnect, OnDisconnect;
|
||||
Host::ThreadEventHandler OnCreate, OnDestroy;
|
||||
Host::ConsoleHandler OnConsole=0;
|
||||
Host::HookInsertHandler HookInsert=0;
|
||||
Host::EmbedCallback embedcallback=0;
|
||||
Host::ConsoleHandler OnConsole = 0;
|
||||
Host::ConsoleHandler OnWarning = 0;
|
||||
Host::HookInsertHandler HookInsert = 0;
|
||||
Host::EmbedCallback embedcallback = 0;
|
||||
void RemoveThreads(std::function<bool(ThreadParam)> removeIf)
|
||||
{
|
||||
std::vector<TextThread*> threadsToRemove;
|
||||
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (removeIf(tp)) threadsToRemove.push_back(&thread);
|
||||
std::vector<TextThread *> threadsToRemove;
|
||||
for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
|
||||
if (removeIf(tp))
|
||||
threadsToRemove.push_back(&thread);
|
||||
for (auto thread : threadsToRemove)
|
||||
{
|
||||
OnDestroy(*thread);
|
||||
@ -76,14 +77,14 @@ namespace
|
||||
void CreatePipe(int pid)
|
||||
{
|
||||
HANDLE
|
||||
hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess),
|
||||
hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE)+std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess);
|
||||
HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid)).c_str());
|
||||
hookPipe = CreateNamedPipeW((std::wstring(HOOK_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, 0, PIPE_BUFFER_SIZE, MAXDWORD, &allAccess),
|
||||
hostPipe = CreateNamedPipeW((std::wstring(HOST_PIPE) + std::to_wstring(pid)).c_str(), PIPE_ACCESS_OUTBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, PIPE_BUFFER_SIZE, 0, MAXDWORD, &allAccess);
|
||||
HANDLE pipeAvailableEvent = CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)).c_str());
|
||||
|
||||
Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT)+std::to_wstring(pid)));
|
||||
Host::AddConsoleOutput((std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(pid)));
|
||||
SetEvent(pipeAvailableEvent);
|
||||
std::thread([hookPipe,hostPipe,pipeAvailableEvent]
|
||||
{
|
||||
std::thread([hookPipe, hostPipe, pipeAvailableEvent]
|
||||
{
|
||||
ConnectNamedPipe(hookPipe, nullptr);
|
||||
CloseHandle(pipeAvailableEvent);
|
||||
BYTE buffer[PIPE_BUFFER_SIZE] = {};
|
||||
@ -141,6 +142,12 @@ namespace
|
||||
Host::AddConsoleOutput(StringToWideString(info.message));
|
||||
}
|
||||
break;
|
||||
case HOST_NOTIFICATION_WARNING:
|
||||
{
|
||||
auto info = *(WarningNotif*)buffer;
|
||||
Host::Warning(StringToWideString(info.message));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
auto data=(TextOutput_T*)buffer;
|
||||
@ -179,8 +186,8 @@ namespace
|
||||
RemoveThreads([&](ThreadParam tp) { return tp.processId == processId; });
|
||||
OnDisconnect(processId);
|
||||
Host::AddConsoleOutput(FormatString(PROC_DISCONN,processId));
|
||||
processRecordsByIds->erase(processId);
|
||||
}).detach();
|
||||
processRecordsByIds->erase(processId); })
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,156 +196,200 @@ namespace Host
|
||||
std::mutex threadmutex;
|
||||
std::mutex outputmutex;
|
||||
std::mutex procmutex;
|
||||
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,bool createconsole)
|
||||
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole)
|
||||
{
|
||||
OnConnect = [=](auto &&...args){std::lock_guard _(procmutex);Connect(std::forward<decltype(args)>(args)...);};
|
||||
OnDisconnect = [=](auto &&...args){std::lock_guard _(procmutex);Disconnect(std::forward<decltype(args)>(args)...);};
|
||||
OnCreate = [=](TextThread& thread) {{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); };
|
||||
OnDestroy = [=](TextThread& thread) {thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} };
|
||||
TextThread::Output = [=](auto &&...args){std::lock_guard _(outputmutex);return Output(std::forward<decltype(args)>(args)...);};
|
||||
OnConnect = [=](auto &&...args)
|
||||
{std::lock_guard _(procmutex);Connect(std::forward<decltype(args)>(args)...); };
|
||||
OnDisconnect = [=](auto &&...args)
|
||||
{std::lock_guard _(procmutex);Disconnect(std::forward<decltype(args)>(args)...); };
|
||||
OnCreate = [=](TextThread &thread)
|
||||
{{std::lock_guard _(threadmutex); Create(thread);} thread.Start(); };
|
||||
OnDestroy = [=](TextThread &thread)
|
||||
{thread.Stop(); {std::lock_guard _(threadmutex); Destroy(thread);} };
|
||||
TextThread::Output = [=](auto &&...args)
|
||||
{std::lock_guard _(outputmutex);return Output(std::forward<decltype(args)>(args)...); };
|
||||
|
||||
if(createconsole){
|
||||
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{} ,CONSOLE ).first->second);
|
||||
if (createconsole)
|
||||
{
|
||||
OnCreate(textThreadsByParams->try_emplace(console, console, HookParam{}, CONSOLE).first->second);
|
||||
Host::AddConsoleOutput(ProjectHomePage);
|
||||
}
|
||||
|
||||
//CreatePipe();
|
||||
|
||||
// CreatePipe();
|
||||
}
|
||||
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed){
|
||||
Start(Connect,Disconnect,Create,Destroy,Output,false);
|
||||
|
||||
OnConsole=[=](auto &&...args){std::lock_guard _(outputmutex);console(std::forward<decltype(args)>(args)...);};
|
||||
HookInsert=[=](auto &&...args){std::lock_guard _(threadmutex);hookinsert(std::forward<decltype(args)>(args)...);};
|
||||
embedcallback=[=](auto &&...args){std::lock_guard _(outputmutex);embed(std::forward<decltype(args)>(args)...);};
|
||||
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning)
|
||||
{
|
||||
Start(Connect, Disconnect, Create, Destroy, Output, !console.has_value());
|
||||
if (warning.has_value())
|
||||
OnWarning = warning.value();
|
||||
if (console.has_value())
|
||||
OnConsole = [=](auto &&...args)
|
||||
{std::lock_guard _(outputmutex);console.value()(std::forward<decltype(args)>(args)...); };
|
||||
if (hookinsert.has_value())
|
||||
HookInsert = [=](auto &&...args)
|
||||
{std::lock_guard _(threadmutex);hookinsert.value()(std::forward<decltype(args)>(args)...); };
|
||||
if (embed.has_value())
|
||||
embedcallback = [=](auto &&...args)
|
||||
{std::lock_guard _(outputmutex);embed.value()(std::forward<decltype(args)>(args)...); };
|
||||
}
|
||||
constexpr auto PROCESS_INJECT_ACCESS=(
|
||||
PROCESS_CREATE_THREAD |
|
||||
PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE |
|
||||
PROCESS_VM_READ);
|
||||
bool SafeInject(HANDLE process,const std::wstring &location){
|
||||
//#ifdef _WIN64
|
||||
constexpr auto PROCESS_INJECT_ACCESS = (PROCESS_CREATE_THREAD |
|
||||
PROCESS_QUERY_INFORMATION |
|
||||
PROCESS_VM_OPERATION |
|
||||
PROCESS_VM_WRITE |
|
||||
PROCESS_VM_READ);
|
||||
bool SafeInject(HANDLE process, const std::wstring &location)
|
||||
{
|
||||
// #ifdef _WIN64
|
||||
#if 0
|
||||
BOOL invalidProcess = FALSE;
|
||||
IsWow64Process(process, &invalidProcess);
|
||||
if (invalidProcess) return AddConsoleOutput(NEED_32_BIT);
|
||||
#endif
|
||||
bool succ=false;
|
||||
if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
|
||||
bool succ = false;
|
||||
if (LPVOID remoteData = VirtualAllocEx(process, nullptr, (location.size() + 1) * sizeof(wchar_t), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE))
|
||||
{
|
||||
WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr);
|
||||
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
|
||||
{
|
||||
WriteProcessMemory(process, remoteData, location.c_str(), (location.size() + 1) * sizeof(wchar_t), nullptr);
|
||||
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr)){
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
succ=true;
|
||||
}
|
||||
else if (GetLastError() == ERROR_ACCESS_DENIED){
|
||||
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
|
||||
succ=false;
|
||||
}
|
||||
VirtualFreeEx(process, remoteData, 0, MEM_RELEASE);
|
||||
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
succ = true;
|
||||
}
|
||||
return succ;
|
||||
else if (GetLastError() == ERROR_ACCESS_DENIED)
|
||||
{
|
||||
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
|
||||
succ = false;
|
||||
}
|
||||
VirtualFreeEx(process, remoteData, 0, MEM_RELEASE);
|
||||
}
|
||||
return succ;
|
||||
}
|
||||
bool UnSafeInject(HANDLE process,const std::wstring &location){
|
||||
|
||||
bool UnSafeInject(HANDLE process, const std::wstring &location)
|
||||
{
|
||||
|
||||
DWORD64 injectedDll;
|
||||
yapi::YAPICall LoadLibraryW(process, _T("kernel32.dll"), "LoadLibraryW");
|
||||
if(x64)injectedDll = LoadLibraryW.Dw64()(location.c_str());
|
||||
else injectedDll = LoadLibraryW(location.c_str());
|
||||
if(injectedDll)return true;
|
||||
return false;
|
||||
|
||||
if (x64)
|
||||
injectedDll = LoadLibraryW.Dw64()(location.c_str());
|
||||
else
|
||||
injectedDll = LoadLibraryW(location.c_str());
|
||||
if (injectedDll)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool CheckProcess(DWORD processId){
|
||||
if (processId == GetCurrentProcessId()) return false;
|
||||
bool CheckProcess(DWORD processId)
|
||||
{
|
||||
if (processId == GetCurrentProcessId())
|
||||
return false;
|
||||
|
||||
WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(processId));
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS){AddConsoleOutput(ALREADY_INJECTED); return false;}
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
AddConsoleOutput(ALREADY_INJECTED);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool InjectDll(DWORD processId,const std::wstring locationX){
|
||||
bool InjectDll(DWORD processId, const std::wstring locationX)
|
||||
{
|
||||
AutoHandle<> process = OpenProcess(PROCESS_INJECT_ACCESS, FALSE, processId);
|
||||
if(!process)return false;
|
||||
bool proc64=Is64BitProcess(process);
|
||||
auto dllname=proc64?LUNA_HOOK_DLL_64:LUNA_HOOK_DLL_32;
|
||||
std::wstring location =locationX.size()?(locationX+L"\\"+dllname): std::filesystem::path(getModuleFilename().value()).replace_filename(dllname);
|
||||
if (!process)
|
||||
return false;
|
||||
bool proc64 = Is64BitProcess(process);
|
||||
auto dllname = proc64 ? LUNA_HOOK_DLL_64 : LUNA_HOOK_DLL_32;
|
||||
std::wstring location = locationX.size() ? (locationX + L"\\" + dllname) : std::filesystem::path(getModuleFilename().value()).replace_filename(dllname);
|
||||
AddConsoleOutput(location);
|
||||
if(proc64==x64){
|
||||
return (SafeInject(process,location));
|
||||
if (proc64 == x64)
|
||||
{
|
||||
return (SafeInject(process, location));
|
||||
}
|
||||
else
|
||||
{
|
||||
return (UnSafeInject(process, location));
|
||||
}
|
||||
else{
|
||||
return (UnSafeInject(process,location));
|
||||
}
|
||||
}
|
||||
bool CreatePipeAndCheck(DWORD processId){
|
||||
bool CreatePipeAndCheck(DWORD processId)
|
||||
{
|
||||
CreatePipe(processId);
|
||||
return CheckProcess(processId);
|
||||
}
|
||||
void InjectProcess(DWORD processId,const std::wstring locationX)
|
||||
void InjectProcess(DWORD processId, const std::wstring locationX)
|
||||
{
|
||||
|
||||
auto check=CreatePipeAndCheck(processId);
|
||||
if(check==false)return;
|
||||
|
||||
auto check = CreatePipeAndCheck(processId);
|
||||
if (check == false)
|
||||
return;
|
||||
|
||||
std::thread([=]
|
||||
{
|
||||
{
|
||||
if(InjectDll(processId,locationX))return ;
|
||||
AddConsoleOutput(INJECT_FAILED);
|
||||
}).detach();
|
||||
AddConsoleOutput(INJECT_FAILED); })
|
||||
.detach();
|
||||
}
|
||||
|
||||
void DetachProcess(DWORD processId)
|
||||
{
|
||||
auto &prs=processRecordsByIds.Acquire().contents;
|
||||
if(prs.find(processId)==prs.end())return;
|
||||
auto &prs = processRecordsByIds.Acquire().contents;
|
||||
if (prs.find(processId) == prs.end())
|
||||
return;
|
||||
prs.at(processId).Send(HOST_COMMAND_DETACH);
|
||||
}
|
||||
|
||||
void InsertHook(DWORD processId, HookParam hp)
|
||||
{
|
||||
auto &prs=processRecordsByIds.Acquire().contents;
|
||||
if(prs.find(processId)==prs.end())return;
|
||||
auto &prs = processRecordsByIds.Acquire().contents;
|
||||
if (prs.find(processId) == prs.end())
|
||||
return;
|
||||
prs.at(processId).Send(InsertHookCmd(hp));
|
||||
}
|
||||
|
||||
void RemoveHook(DWORD processId, uint64_t address)
|
||||
{
|
||||
auto &prs=processRecordsByIds.Acquire().contents;
|
||||
if(prs.find(processId)==prs.end())return;
|
||||
auto &prs = processRecordsByIds.Acquire().contents;
|
||||
if (prs.find(processId) == prs.end())
|
||||
return;
|
||||
prs.at(processId).Send(RemoveHookCmd(address));
|
||||
}
|
||||
|
||||
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound)
|
||||
{
|
||||
auto &prs=processRecordsByIds.Acquire().contents;
|
||||
if(prs.find(processId)==prs.end())return;
|
||||
if (HookFound) prs.at(processId).OnHookFound = HookFound;
|
||||
auto &prs = processRecordsByIds.Acquire().contents;
|
||||
if (prs.find(processId) == prs.end())
|
||||
return;
|
||||
if (HookFound)
|
||||
prs.at(processId).OnHookFound = HookFound;
|
||||
prs.at(processId).Send(FindHookCmd(sp));
|
||||
}
|
||||
|
||||
TextThread& GetThread(ThreadParam tp)
|
||||
TextThread &GetThread(ThreadParam tp)
|
||||
{
|
||||
return textThreadsByParams->at(tp);
|
||||
}
|
||||
|
||||
TextThread* GetThread(int64_t handle)
|
||||
TextThread *GetThread(int64_t handle)
|
||||
{
|
||||
for (auto& [tp, thread] : textThreadsByParams.Acquire().contents) if (thread.handle == handle) return &thread;
|
||||
return nullptr;
|
||||
for (auto &[tp, thread] : textThreadsByParams.Acquire().contents)
|
||||
if (thread.handle == handle)
|
||||
return &thread;
|
||||
return nullptr;
|
||||
}
|
||||
EmbedSharedMem* GetEmbedSharedMem(DWORD processId){
|
||||
auto &prs=processRecordsByIds.Acquire().contents;
|
||||
if(prs.find(processId)==prs.end())return 0;
|
||||
EmbedSharedMem *GetEmbedSharedMem(DWORD processId)
|
||||
{
|
||||
auto &prs = processRecordsByIds.Acquire().contents;
|
||||
if (prs.find(processId) == prs.end())
|
||||
return 0;
|
||||
return prs.at(processId).embedsharedmem;
|
||||
}
|
||||
void AddConsoleOutput(std::wstring text)
|
||||
{
|
||||
if(OnConsole)
|
||||
if (OnConsole)
|
||||
OnConsole(std::move(text));
|
||||
else
|
||||
GetThread(console).AddSentence(std::move(text));
|
||||
}
|
||||
void Warning(std::wstring text)
|
||||
{
|
||||
if (OnWarning)
|
||||
OnWarning(text);
|
||||
AddConsoleOutput(L"[Warning] " + text);
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,15 @@
|
||||
#include "textthread.h"
|
||||
namespace Host
|
||||
{
|
||||
using ConsoleHandler =std::function<void(const std::wstring&)>;
|
||||
using ConsoleHandler = std::function<void(const std::wstring &)>;
|
||||
using ProcessEventHandler = std::function<void(DWORD)>;
|
||||
using ThreadEventHandler = std::function<void(TextThread&)>;
|
||||
using HookEventHandler = std::function<void(const HookParam&,const std::wstring& text)>;
|
||||
using HookInsertHandler= std::function<void(uint64_t,const std::wstring&)>;
|
||||
using EmbedCallback= std::function<void(const std::wstring&,const ThreadParam&)>;
|
||||
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,bool createconsole=true);
|
||||
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output,ConsoleHandler console,HookInsertHandler hookinsert,EmbedCallback embed);
|
||||
void InjectProcess(DWORD processId,const std::wstring locationX=L"");
|
||||
using ThreadEventHandler = std::function<void(TextThread &)>;
|
||||
using HookEventHandler = std::function<void(const HookParam &, const std::wstring &text)>;
|
||||
using HookInsertHandler = std::function<void(uint64_t, const std::wstring &)>;
|
||||
using EmbedCallback = std::function<void(const std::wstring &, const ThreadParam &)>;
|
||||
void Start(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, bool createconsole = true);
|
||||
void StartEx(ProcessEventHandler Connect, ProcessEventHandler Disconnect, ThreadEventHandler Create, ThreadEventHandler Destroy, TextThread::OutputCallback Output, std::optional<ConsoleHandler> console, std::optional<HookInsertHandler> hookinsert, std::optional<EmbedCallback> embed, std::optional<ConsoleHandler> warning);
|
||||
void InjectProcess(DWORD processId, const std::wstring locationX = L"");
|
||||
bool CreatePipeAndCheck(DWORD processId);
|
||||
|
||||
void DetachProcess(DWORD processId);
|
||||
@ -19,13 +19,14 @@ namespace Host
|
||||
void InsertHook(DWORD processId, HookParam hp);
|
||||
void RemoveHook(DWORD processId, uint64_t address);
|
||||
void FindHooks(DWORD processId, SearchParam sp, HookEventHandler HookFound = {});
|
||||
EmbedSharedMem* GetEmbedSharedMem(DWORD pid);
|
||||
TextThread* GetThread(int64_t handle);
|
||||
TextThread& GetThread(ThreadParam tp);
|
||||
EmbedSharedMem *GetEmbedSharedMem(DWORD pid);
|
||||
TextThread *GetThread(int64_t handle);
|
||||
TextThread &GetThread(ThreadParam tp);
|
||||
|
||||
void AddConsoleOutput(std::wstring text);
|
||||
void Warning(std::wstring text);
|
||||
|
||||
inline int defaultCodepage = SHIFT_JIS;
|
||||
|
||||
constexpr ThreadParam console{ 0, 0, 0, 0 };
|
||||
constexpr ThreadParam console{0, 0, 0, 0};
|
||||
}
|
||||
|
@ -1,27 +1,28 @@
|
||||
#include "textthread.h"
|
||||
#include "host.h"
|
||||
#include"Lang/Lang.h"
|
||||
#include "Lang/Lang.h"
|
||||
|
||||
// return true if repetition found (see https://github.com/Artikash/Textractor/issues/40)
|
||||
static bool RemoveRepetition(std::wstring& text)
|
||||
static bool RemoveRepetition(std::wstring &text)
|
||||
{
|
||||
wchar_t* end = text.data() + text.size();
|
||||
wchar_t *end = text.data() + text.size();
|
||||
for (int length = text.size() / 3; length > 6; --length)
|
||||
if (memcmp(end - length * 3, end - length * 2, length * sizeof(wchar_t)) == 0 && memcmp(end - length * 3, end - length * 1, length * sizeof(wchar_t)) == 0)
|
||||
return RemoveRepetition(text = std::wstring(end - length, length)), true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) :
|
||||
handle(threadCounter++),
|
||||
name(name.value_or(StringToWideString(hp.name))),
|
||||
tp(tp),
|
||||
hp(hp)
|
||||
{}
|
||||
TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name) : handle(threadCounter++),
|
||||
name(name.value_or(StringToWideString(hp.name))),
|
||||
tp(tp),
|
||||
hp(hp)
|
||||
{
|
||||
}
|
||||
|
||||
void TextThread::Start()
|
||||
{
|
||||
CreateTimerQueueTimer(&timer, NULL, [](void* This, auto) { ((TextThread*)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION);
|
||||
CreateTimerQueueTimer(&timer, NULL, [](void *This, auto)
|
||||
{ ((TextThread *)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION);
|
||||
}
|
||||
|
||||
void TextThread::Stop()
|
||||
@ -34,9 +35,10 @@ void TextThread::AddSentence(std::wstring sentence)
|
||||
queuedSentences->emplace_back(std::move(sentence));
|
||||
}
|
||||
|
||||
void TextThread::Push(BYTE* data, int length)
|
||||
void TextThread::Push(BYTE *data, int length)
|
||||
{
|
||||
if (length < 0) return;
|
||||
if (length < 0)
|
||||
return;
|
||||
std::scoped_lock lock(bufferMutex);
|
||||
|
||||
BYTE doubleByteChar[2];
|
||||
@ -56,19 +58,23 @@ void TextThread::Push(BYTE* data, int length)
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
auto converted = commonparsestring(data,length,&hp,Host::defaultCodepage);
|
||||
if(converted)
|
||||
auto converted = commonparsestring(data, length, &hp, Host::defaultCodepage);
|
||||
if (converted)
|
||||
{
|
||||
buffer.append(converted.value());
|
||||
if (hp.type & FULL_STRING && converted.value().size()>1) buffer.push_back(L'\n');
|
||||
if (hp.type & FULL_STRING && converted.value().size() > 1)
|
||||
buffer.push_back(L'\n');
|
||||
}
|
||||
else Host::AddConsoleOutput(INVALID_CODEPAGE);
|
||||
else
|
||||
Host::AddConsoleOutput(INVALID_CODEPAGE);
|
||||
|
||||
lastPushTime = GetTickCount64();
|
||||
|
||||
|
||||
if (filterRepetition)
|
||||
{
|
||||
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch) { return repeatingChars.find(ch) != repeatingChars.end(); })) buffer.clear();
|
||||
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t ch)
|
||||
{ return repeatingChars.find(ch) != repeatingChars.end(); }))
|
||||
buffer.clear();
|
||||
if (RemoveRepetition(buffer)) // sentence repetition detected, which means the entire sentence has already been received
|
||||
{
|
||||
repeatingChars = std::unordered_set(buffer.begin(), buffer.end());
|
||||
@ -84,7 +90,7 @@ void TextThread::Push(BYTE* data, int length)
|
||||
}
|
||||
}
|
||||
|
||||
void TextThread::Push(const wchar_t* data)
|
||||
void TextThread::Push(const wchar_t *data)
|
||||
{
|
||||
std::scoped_lock lock(bufferMutex);
|
||||
// not sure if this should filter repetition
|
||||
@ -96,21 +102,24 @@ void TextThread::Flush()
|
||||
{
|
||||
{
|
||||
auto storage = this->storage.Acquire();
|
||||
if (storage->size() > maxHistorySize) storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983
|
||||
if (storage->size() > maxHistorySize)
|
||||
storage->erase(0, storage->size() - maxHistorySize); // https://github.com/Artikash/Textractor/issues/127#issuecomment-486882983
|
||||
}
|
||||
|
||||
std::vector<std::wstring> sentences;
|
||||
queuedSentences->swap(sentences);
|
||||
int totalSize = 0;
|
||||
for (auto& sentence : sentences)
|
||||
for (auto &sentence : sentences)
|
||||
{
|
||||
totalSize += sentence.size();
|
||||
sentence.erase(std::remove(sentence.begin(), sentence.end(), 0), sentence.end());
|
||||
if (Output(*this, sentence)) storage->append(sentence+L"\n");
|
||||
if (Output(*this, sentence))
|
||||
storage->append(sentence + L"\n");
|
||||
}
|
||||
|
||||
std::scoped_lock lock(bufferMutex);
|
||||
if (buffer.empty()) return;
|
||||
if (buffer.empty())
|
||||
return;
|
||||
if (buffer.size() > maxBufferSize || GetTickCount64() - lastPushTime > flushDelay)
|
||||
{
|
||||
AddSentence(std::move(buffer));
|
||||
|
@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
class TextThread
|
||||
{
|
||||
public:
|
||||
using OutputCallback = std::function<bool(TextThread&, std::wstring&)>;
|
||||
using OutputCallback = std::function<bool(TextThread &, std::wstring &)>;
|
||||
inline static OutputCallback Output;
|
||||
|
||||
inline static bool filterRepetition = false;
|
||||
inline static int flushDelay = 100;
|
||||
inline static int flushDelay = 100;
|
||||
inline static int maxBufferSize = 3000;
|
||||
inline static int maxHistorySize = 10'000'000;
|
||||
|
||||
@ -17,8 +16,8 @@ public:
|
||||
void Start();
|
||||
void Stop();
|
||||
void AddSentence(std::wstring sentence);
|
||||
void Push(BYTE* data, int length);
|
||||
void Push(const wchar_t* data);
|
||||
void Push(BYTE *data, int length);
|
||||
void Push(const wchar_t *data);
|
||||
|
||||
Synchronized<std::wstring> storage;
|
||||
const int64_t handle;
|
||||
@ -37,6 +36,9 @@ private:
|
||||
std::mutex bufferMutex;
|
||||
DWORD64 lastPushTime = 0;
|
||||
Synchronized<std::vector<std::wstring>> queuedSentences;
|
||||
struct TimerDeleter { void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); } };
|
||||
struct TimerDeleter
|
||||
{
|
||||
void operator()(HANDLE h) { DeleteTimerQueueTimer(NULL, h, INVALID_HANDLE_VALUE); }
|
||||
};
|
||||
AutoHandle<TimerDeleter> timer = NULL;
|
||||
};
|
||||
|
@ -38,7 +38,8 @@ enum HostNotificationType
|
||||
HOST_NOTIFICATION_FOUND_HOOK,
|
||||
HOST_NOTIFICATION_RMVHOOK,
|
||||
HOST_NOTIFICATION_INSERTING_HOOK,
|
||||
HOST_SETTEXTTHREADTYPE
|
||||
HOST_SETTEXTTHREADTYPE,
|
||||
HOST_NOTIFICATION_WARNING
|
||||
};
|
||||
#define NEXT_MASK(x) \
|
||||
DUMMY1_##x, \
|
||||
|
@ -183,6 +183,12 @@ struct ConsoleOutputNotif // From dll
|
||||
HostNotificationType command = HOST_NOTIFICATION_TEXT;
|
||||
char message[MESSAGE_SIZE] = {};
|
||||
};
|
||||
struct WarningNotif // From dll
|
||||
{
|
||||
WarningNotif(std::string message = "") { strncpy_s(this->message, message.c_str(), MESSAGE_SIZE - 1); }
|
||||
HostNotificationType command = HOST_NOTIFICATION_WARNING;
|
||||
char message[MESSAGE_SIZE] = {};
|
||||
};
|
||||
|
||||
struct HookFoundNotif // From dll
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user