This commit is contained in:
恍兮惚兮 2024-10-03 14:53:59 +08:00
parent 1016b82df0
commit 163835bec9
61 changed files with 4928 additions and 3780 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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");
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()||_;
bool all()
{
auto _ = _1();
_ = _2() || _;
_ = _3() || _;
return _;
}
}
bool AGES7::attach_function(){
bool AGES7::attach_function()
{
return all();
}

View File

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

View File

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

View File

@ -1,11 +1,13 @@
class Artemis:public ENGINE{
public:
Artemis(){
class Artemis : public ENGINE
{
public:
Artemis()
{
check_by=CHECK_BY::FILE;
check_by_target=L"*.pfs";
check_by = CHECK_BY::FILE;
check_by_target = L"*.pfs";
};
bool attach_function();
};

View File

@ -1,57 +1,68 @@
#include"CMVS.h"
namespace{
bool EMbed(){
//有多个,但是只有最后一个是有效的
#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,
//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;
bool res = false;
auto addr = processStartAddress;
std::vector<uintptr_t>already;
std::vector<uintptr_t> already;
while(addr){
addr = MemDbg::findBytes(bytes,sizeof(bytes),addr+1,processStopAddress);
if(addr==0)continue;
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()){
if (already.size())
{
HookParam hp;
hp.address = already.back() ;
hp.offset=get_reg(regs::rdx);
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.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;
}
}
bool CMVSh() {
bool CMVSh()
{
DWORD align = 0xCCCCCCCC;
auto addr = MemDbg::findCallerAddress((uintptr_t)::GetGlyphOutlineA, align, processStartAddress, processStopAddress);
if (!addr) return false;
if (!addr)
return false;
HookParam hp;
hp.address = addr+4;
hp.offset=get_reg(regs::r8);
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;
}

View File

@ -1,15 +1,16 @@
class CMVS:public ENGINE{
public:
CMVS(){
check_by=CHECK_BY::FILE;
check_by_target=L"data\\pack\\*.cpz";
class CMVS : public ENGINE
{
public:
CMVS()
{
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")) {
// if (wcsstr(str,L"cmvs32") || wcsstr(str,L"cmvs64")) {
// InsertCMVSHook();
// return true;
//}

View File

@ -1,23 +1,26 @@
#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
// 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.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";
@ -28,7 +31,8 @@ bool InsertGodotHook_X64() {
ConsoleOutput("Godot_x64: pattern not found");
return false;
}
bool InsertGodotHook2_X64() {
bool InsertGodotHook2_X64()
{
/*
* Sample games:
@ -45,10 +49,11 @@ bool InsertGodotHook2_X64() {
};
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 _;
}

View File

@ -1,11 +1,13 @@
class Godot:public ENGINE{
public:
Godot(){
class Godot : public ENGINE
{
public:
Godot()
{
check_by=CHECK_BY::FILE;
check_by_target=L"*.pck";
check_by = CHECK_BY::FILE;
check_by_target = L"*.pck";
};
bool attach_function();
};

View File

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

View File

@ -26,15 +26,17 @@
// }
// }
class Kincaid:public ENGINE{
public:
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");
check_by = CHECK_BY::CUSTOM;
check_by_target = []()
{
return Util::SearchResourceString(L"Cookiedraggy") || Util::SearchResourceString(L"The Adventures of Kincaid");
};
};
bool attach_function();
};

View File

@ -1,6 +1,6 @@
#include"KiriKiri.h"
#include "KiriKiri.h"
bool InsertKiriKiriZHook()
{
{
/*
* Sample games:
@ -22,38 +22,40 @@ bool InsertKiriKiriZHook()
};
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 + 1;
hp.offset=get_reg(regs::rcx);
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
};
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) {
for (auto addr : addrs)
{
ConsoleOutput("krkrz64 %p", addr);
const BYTE funcstart[] = { 0xcc,0xcc,0xcc,0xcc };
const BYTE funcstart[] = {0xcc, 0xcc, 0xcc, 0xcc};
addr = reverseFindBytes(funcstart, sizeof(funcstart), addr - 0x1000, addr);
if (addr == 0)continue;
if (addr == 0)
continue;
addr += 4;
HookParam hp;
hp.address = addr;
hp.type = CODEC_UTF16| DATA_INDIRECT;
hp.offset=get_reg(regs::rcx);
hp.type = CODEC_UTF16 | DATA_INDIRECT;
hp.offset = get_reg(regs::rcx);
hp.index = 0x18;
ConsoleOutput("krkrz64 %p %x", addr);
return NewHook(hp, "krkrz64");
@ -62,7 +64,7 @@ bool Insertkrkrz64Hook()
ConsoleOutput("krkrz64 failed");
return false;
}
bool KiriKiri::attach_function() {
return Insertkrkrz64Hook()||InsertKiriKiriZHook();
bool KiriKiri::attach_function()
{
return Insertkrkrz64Hook() || InsertKiriKiriZHook();
}

View File

@ -1,15 +1,17 @@
class KiriKiri:public ENGINE{
public:
KiriKiri(){
class KiriKiri : public ENGINE
{
public:
KiriKiri()
{
check_by=CHECK_BY::CUSTOM;
is_engine_certain=false;
check_by_target=[](){
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();
};

View File

@ -1,13 +1,14 @@
class LightVN:public ENGINE{
public:
LightVN(){
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"};
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();
};

View File

@ -1,5 +1,5 @@
#include"PPSSPP.h"
#include"ppsspp/psputils.hpp"
#include "PPSSPP.h"
#include "ppsspp/psputils.hpp"
bool PPSSPPengine::attach_function()
{

View File

@ -1,12 +1,14 @@
class PPSSPPengine:public ENGINE{
public:
PPSSPPengine(){
class PPSSPPengine : public ENGINE
{
public:
PPSSPPengine()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"PPSSPP*.exe";
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"PPSSPP*.exe";
};
bool attach_function();
};

View File

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

View File

@ -1,18 +1,21 @@
#include"Suika2.h"
#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;
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");
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 ;
bool Suika2::attach_function()
{
auto _1 = Suika2_msvcrt();
return _1;
}

View File

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

View File

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

View File

@ -1,13 +1,14 @@
class TYPEMOON:public ENGINE{
public:
TYPEMOON(){
class TYPEMOON : public ENGINE
{
public:
TYPEMOON()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"data*.hfa";
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"data*.hfa";
};
bool attach_function();
};

View File

@ -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_() {
bool V8::attach_function_()
{
return tryhookv8();
}

View File

@ -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() { return true; }
};

View File

@ -1,17 +1,18 @@
#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");

View File

@ -1,13 +1,14 @@
class YOX:public ENGINE{
public:
YOX(){
class YOX : public ENGINE
{
public:
YOX()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"base/*.dat";
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"base/*.dat";
};
bool attach_function();
};

View File

@ -1,41 +1,42 @@
#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
// .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;
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.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)
{
auto ptr = stack->rdx;
auto size = stack->r8;
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE) )//否则有短acsii
if (size == strnlen((char *)ptr, TEXT_BUFFER_SIZE)) // 否则有短acsii
{
*data = ptr;
*len = size;
@ -45,5 +46,5 @@ bool livecaptions::attach_function()
}
};
return NewHook(hp,"vcruntime140_app:memmove");
return NewHook(hp, "vcruntime140_app:memmove");
}

View File

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

View File

@ -1,13 +1,14 @@
class lucasystem:public ENGINE{
public:
lucasystem(){
class lucasystem : public ENGINE
{
public:
lucasystem()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"files/*.PAK";
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"files/*.PAK";
};
bool attach_function();
};

View File

@ -1,18 +1,21 @@
#include"mono.h"
#include"mono/monocommon.hpp"
#include "mono.h"
#include "mono/monocommon.hpp"
namespace{
bool monobdwgc() {
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
0x81, 0xF9, 0x80, 0x00, 0x00, 0x00,
0x73, 0x05,
0x49, 0x8B, 0xCC
/*
_BYTE *__fastcall sub_18005B290(
_BYTE *__fastcall sub_18005B290(
_WORD *a1,
int a2,
__int64 a3,
@ -37,46 +40,51 @@ _BYTE *__fastcall sub_18005B290(
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){
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;
std::wstring str = std::wstring((LPWSTR)*data );
*split=str.find(L"OnShowComplete")!=str.npos;
*len = wcslen((wchar_t*)*data) * 2 ;
*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, 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::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;
}

View File

@ -1,10 +1,12 @@
class mono:public ENGINE{
public:
mono(){
class mono : public ENGINE
{
public:
mono()
{
check_by=CHECK_BY::ALL_TRUE;
check_by = CHECK_BY::ALL_TRUE;
};
bool attach_function();
};

View File

@ -1,10 +1,14 @@
#include"pchooks.h"
#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);
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();

View File

@ -1,11 +1,13 @@
class pchooks:public ENGINE{
public:
pchooks(){
class pchooks : public ENGINE
{
public:
pchooks()
{
check_by=CHECK_BY::ALL_TRUE;
dontstop=true;
check_by = CHECK_BY::ALL_TRUE;
dontstop = true;
};
bool attach_function();
};

View File

@ -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
#endif
uintptr_t getDoJitAddress() {
//rpcs3/Emu/Cell/PPUThread.cpp
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,60 +140,70 @@ 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{
struct emfuncinfo
{
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const char* _id;
int argidx;
int padding;
void *hookfunc;
void *filterfun;
const char *_id;
};
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
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;
}
}
static std::set<std::pair<uintptr_t,uintptr_t>> timeoutbreaks;
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);
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);
}
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
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)
@ -200,68 +212,75 @@ bool unsafeinithooks(){
}
*/
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)
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);
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");
}
return NewHook(hp, "g_exec_addr");
}
}
bool rpcs3::attach_function()
{
ConsoleOutput("[Compatibility] RPCS3");
auto DoJitPtr=getDoJitAddress();
if(DoJitPtr==0)return false;
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);
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={
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"}},
{0x46328, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM61131"}},
// Dunamis15
{0x42c90, {CODEC_UTF8, 1, 0, 0, FBLJM61131, "BLJM60347"}},
};
return 1;
}();
}();
}

View File

@ -1,13 +1,14 @@
class rpcs3:public ENGINE{
public:
rpcs3(){
class rpcs3 : public ENGINE
{
public:
rpcs3()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"rpcs3.exe";
check_by = CHECK_BY::FILE;
is_engine_certain = false;
check_by_target = L"rpcs3.exe";
};
bool attach_function();
};

View File

@ -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{
struct emfuncinfo
{
uint64_t type;
int argidx;int padding;
void* hookfunc;
void* filterfun;
const char* _id;
int argidx;
int padding;
void *hookfunc;
void *filterfun;
const char *_id;
};
std::unordered_map<uintptr_t,emfuncinfo>emfunctionhooks;
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;
}
}
}
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;
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;
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;
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);
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);
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);
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);
}
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;
}
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);
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);
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);
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);
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);
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);
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::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);
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);
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);
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);
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"");
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){
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;
BYTE pattern[] = {0x47, 0xff, 0xff};
auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50);
if (!results)
return;
address = results+5;
address = results + 5;
while (true) {
std::string text= (char*)address;
while (true)
{
std::string text = (char *)address;
final_string += text;
address = address+(text.size() + 1);
address = address + (text.size() + 1);
auto bytes=(BYTE*)address;
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);
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);
write_string_new(data, len, final_string);
}
static int fm=0;
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 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,? */) {
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) {
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 /* */) {
if (c == 0x815e /* */)
{
s += ' '; // single line
}
else if (buf[0] == 0) {
else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER
// do nothing
if (buf[1] == 0x4e) {
if (buf[1] == 0x4e)
{
s += "PLAYER";
fm++;
}
}
else {
s+=buf;
else
{
s += buf;
}
i += 2;
}
return s;
}(p);
if(b>0){
if (b > 0)
{
fm--;
return;
}
if(s==pre)return ;
pre=s;
write_string_new(data,len,s);
}
if (s == pre)
return;
pre = s;
write_string_new(data, len, s);
}
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
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-
// {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"}},
{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;
}();
}();
}

View File

@ -1,13 +1,14 @@
class vita3k:public ENGINE{
public:
vita3k(){
class vita3k : public ENGINE
{
public:
vita3k()
{
check_by=CHECK_BY::FILE;
is_engine_certain=false;
check_by_target=L"Vita3K.exe";
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

File diff suppressed because it is too large Load Diff

17
LunaHook/engine64/yuzu.h Normal file
View 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

View File

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

View File

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

View File

@ -1,81 +1,95 @@
#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);
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);
return write_string_overwrite(data, len, result);
}
static int fm=0;
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 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,? */) {
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) {
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 /* */) {
if (c == 0x815e /* */)
{
s += ' '; // single line
}
else if (buf[0] == 0) {
else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER
// do nothing
if (buf[1] == 0x4e) {
if (buf[1] == 0x4e)
{
s += "PLAYER";
fm++;
}
}
else {
s+=buf;
else
{
s += buf;
}
i += 2;
}
return s;
}(p);
if(b>0){
if (b > 0)
{
fm--;
return;
}
if(s==pre)return ;
pre=s;
write_string_new(data,len,s);
}
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();
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" ");
@ -84,16 +98,18 @@ bool NPJH50909_filter(void* data, size_t* len, HookParam* hp){
// Reformat name
std::wsmatch match;
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「"))) {
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));
}
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);
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, "");
@ -106,131 +122,156 @@ bool ULJM06119_filter(void* data, size_t* len, HookParam* hp){
std::regex newlinePattern(R"(/\n+)");
s = std::regex_replace(s, newlinePattern, " ");
return write_string_overwrite(data,len,s);
}
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);
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)
return write_string_overwrite(data, len, result);
}
std::string s;int i=0;uint8_t c;
while ((c = *(uint8_t*)(address+i)) != 0) {
if (c == 0x1b) {
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));
c = *(uint8_t *)(address + (i + 1));
if (c == 0x7f)
i += 5;
else
i += 2;
}
else if (c == 0x0a) {
else if (c == 0x0a)
{
s += '\n';
i += 1;
}
else if (c == 0x20) {
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
{
auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i)));
s += std::string((char *)(address + i), len);
i += len; // encoder.encode(c).byteLength;
}
}
return s;
}
}
}
void ULJM05428(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
auto address= PPSSPP::emu_arg(stack)[1];
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);
}
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
write_string_new(data, len, s);
}
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);
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];
auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s=Corda::readBinaryString(address,&haveNamve);
*split=haveNamve;
write_string_new(data,len,s);
}
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);
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);
}
return write_string_overwrite(data, len, result2);
}
bool FULJM05603(LPVOID data, size_t* size, HookParam*)
{
bool FULJM05603(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t*>(size);
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{
}
namespace NPJH50530
{
std::string current;
bool T(LPVOID data, size_t* size, HookParam*)
{
current=std::string((char*)data,*size);
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*)
{
}
bool N(LPVOID data, size_t *size, HookParam *)
{
auto current1 = std::string((char *)data, *size);
return current != current1;
}
}
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;
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';
if (text[i] == '^')
text[i] = '\n';
i+=1;
i += 1;
}
return true;
}
}
bool NPJH50619F(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
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);
@ -243,12 +284,12 @@ bool NPJH50619F(void* data, size_t* len, HookParam* hp){
std::regex pattern4("(#.+?\\))+");
std::string replacement4 = "";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
return write_string_overwrite(data,len,result4);
}
return write_string_overwrite(data, len, result4);
}
bool NPJH50505F(void* data, size_t* len, HookParam* hp){
auto s = std::string((char*)data,*len);
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 = "";
@ -270,60 +311,67 @@ bool NPJH50505F(void* data, size_t* len, HookParam* hp){
std::string replacement6 = " ";
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
return write_string_overwrite(data,len,result6);
}
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;
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
};
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
// ティアーズ・トゥ・ティアラ 外伝 アヴァロンの謎
{0x890A4BC, {CODEC_UTF16, 1, 0, 0, FNPJH50243, "NPJH50243"}},
// 薔薇ノ木ニ薔薇ノ花咲ク
{0x881E560, {0, 1, 0, 0, 0, "ULJM05802"}},
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,14 +2,13 @@
#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,
@ -22,51 +21,65 @@ 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](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));
}
});
}
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();
@ -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);

View File

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

View File

@ -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())),
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));
//放到构造表里就不行,不知道为何。
embedsharedmem = (EmbedSharedMem *)MapViewOfFile(mappedFile2, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(EmbedSharedMem));
// 放到构造表里就不行,不知道为何。
}
~ProcessRecord()
@ -27,9 +26,8 @@ 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)
@ -37,8 +35,8 @@ namespace
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,13 +77,13 @@ 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);
@ -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 |
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
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;
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)){
if (AutoHandle<> thread = CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)LoadLibraryW, remoteData, 0, nullptr))
{
WaitForSingleObject(thread, INFINITE);
succ=true;
succ = true;
}
else if (GetLastError() == ERROR_ACCESS_DENIED){
else if (GetLastError() == ERROR_ACCESS_DENIED)
{
AddConsoleOutput(NEED_64_BIT); // https://stackoverflow.com/questions/16091141/createremotethread-access-denied
succ=false;
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;
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;
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);
}
}

View File

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

View File

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

View File

@ -1,10 +1,9 @@
#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;
@ -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;
};

View File

@ -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, \

View File

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