Update v8.cpp

Update lunajspatch.js

Update v8.cpp
This commit is contained in:
恍兮惚兮 2024-03-15 21:51:59 +08:00
parent a184ebae85
commit 7be474802a
7 changed files with 278 additions and 105 deletions

View File

@ -1,5 +1,5 @@
#include"V8.h" #include"V8.h"
#include"v8/v8.h"
/** /**
* Artikash 7/15/2018: Insert Tyranobuilder hook * Artikash 7/15/2018: Insert Tyranobuilder hook
* Sample game: https://vndb.org/v22252: /HWN-8:-1C@233A54:yuika_t.exe * Sample game: https://vndb.org/v22252: /HWN-8:-1C@233A54:yuika_t.exe
@ -105,53 +105,6 @@ bool hookv8exports(HMODULE module) {
return NewHook(hp, "Write@String@v8"); return NewHook(hp, "Write@String@v8");
} }
namespace{
bool hookstringlength(HMODULE hm){
auto Length=GetProcAddress(hm,"?Length@String@v8@@QBEHXZ");
static uintptr_t WriteUtf8;
static uintptr_t Utf8Length;
WriteUtf8=(uintptr_t)GetProcAddress(hm,"?WriteUtf8@String@v8@@QBEHPADHPAHH@Z");
Utf8Length=(uintptr_t)GetProcAddress(hm,"?Utf8Length@String@v8@@QBEHXZ");
if(Length==0||WriteUtf8==0||Utf8Length==0)return false;
HookParam hp;
hp.address=(uintptr_t)Length;
hp.type=USING_STRING|CODEC_UTF8;
hp.text_fun=
[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
{
auto length=((size_t(__thiscall*)(void*))Utf8Length)((void*)stack->ecx);
if(!length)return;
auto u8str=new char[length+1];
int writen;
((size_t(__thiscall*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->ecx,u8str,length,&writen,0);
*data=(uintptr_t)u8str;
*len=length;
};
return NewHook(hp,"v8::String::Length");
}
}
namespace{
bool hookClipboard(){
HookParam hp;
hp.address=(uintptr_t)SetClipboardData;
hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE;
hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){
HGLOBAL hClipboardData=(HGLOBAL)stack->stack[2];
*data=(uintptr_t)GlobalLock(hClipboardData);
*len=wcslen((wchar_t*)*data)*2;
GlobalUnlock(hClipboardData);
};
hp.hook_after=[](hook_stack*s,void* data, size_t len){
HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2);
auto pchData = (wchar_t*)GlobalLock(hClipboardData);
wcscpy(pchData, (wchar_t*)data);
GlobalUnlock(hClipboardData);
s->stack[2]=(uintptr_t)hClipboardData;
};
return NewHook(hp,"hookClipboard");
}
}
bool V8::attach_function_() { bool V8::attach_function_() {
for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) { for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) {
auto hm=GetModuleHandleW(moduleName); auto hm=GetModuleHandleW(moduleName);
@ -161,9 +114,8 @@ bool V8::attach_function_() {
bool b1= InsertV8Hook(hm); bool b1= InsertV8Hook(hm);
bool b2=hookv8addr(hm); bool b2=hookv8addr(hm);
bool b3=hookv8exports(hm); bool b3=hookv8exports(hm);
b1=hookstringlength(hm)||b1; b1=tryhookv8(hm)||b1;
if(b1||b2||b3){ if(b1||b2||b3){
hookClipboard();
return true; return true;
} }
} }

View File

@ -1,6 +1,5 @@
#include"V8.h" #include"V8.h"
#include"v8/v8.h"
// Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write // Artikash 6/23/2019: V8 (JavaScript runtime) has rcx = string** at v8::String::Write
// sample game https://www.freem.ne.jp/dl/win/18963 // sample game https://www.freem.ne.jp/dl/win/18963
bool InsertV8Hook(HMODULE module) bool InsertV8Hook(HMODULE module)
@ -259,65 +258,16 @@ namespace{
return innerHTML(module)|| success; return innerHTML(module)|| success;
} }
} }
namespace{
bool hookstringlength(HMODULE hm){
auto Length=GetProcAddress(hm,"?Length@String@v8@@QEBAHXZ");
static uintptr_t WriteUtf8;
static uintptr_t Utf8Length;
WriteUtf8=(uintptr_t)GetProcAddress(hm,"?WriteUtf8@String@v8@@QEBAHPEADHPEAHH@Z");
Utf8Length=(uintptr_t)GetProcAddress(hm,"?Utf8Length@String@v8@@QEBAHXZ");
if(Length==0||WriteUtf8==0||Utf8Length==0)return false;
HookParam hp;
hp.address=(uintptr_t)Length;
hp.type=USING_STRING|CODEC_UTF8;
hp.text_fun=
[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
{
auto length=((size_t(*)(void*))Utf8Length)((void*)stack->rcx);
if(!length)return;
auto u8str=new char[length+1];
int writen;
((size_t(*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->rcx,u8str,length,&writen,0);
*data=(uintptr_t)u8str;
*len=length;
};
return NewHook(hp,"v8::String::Length");
}
}
namespace{
bool hookClipboard(){
HookParam hp;
hp.address=(uintptr_t)SetClipboardData;
hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE;
hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){
HGLOBAL hClipboardData=(HGLOBAL)stack->rdx;
*data=(uintptr_t)GlobalLock(hClipboardData);
*len=wcslen((wchar_t*)*data)*2;
GlobalUnlock(hClipboardData);
};
hp.hook_after=[](hook_stack*s,void* data, size_t len){
HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2);
auto pchData = (wchar_t*)GlobalLock(hClipboardData);
wcscpy(pchData, (wchar_t*)data);
GlobalUnlock(hClipboardData);
s->rdx=(uintptr_t)hClipboardData;
};
return NewHook(hp,"hookClipboard");
}
}
bool V8::attach_function_() { bool V8::attach_function_() {
for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) { for (const wchar_t* moduleName : { (const wchar_t*)NULL, L"node.dll", L"nw.dll" }) {
auto hm=GetModuleHandleW(moduleName); auto hm=GetModuleHandleW(moduleName);
if(hm==0)continue; if(hm==0)continue;
bool ok=InsertV8Hook(hm); bool ok=InsertV8Hook(hm);
ok= hookv8exports(hm)||ok; ok= hookv8exports(hm)||ok;
ok=hookstringlength(hm)||ok;
ok=addhooks(hm)||ok; ok=addhooks(hm)||ok;
if(ok){ ok=tryhookv8(hm);
hookClipboard(); if(ok) return true;
return true;
}
} }
return false; return false;
} }

View File

@ -1,4 +1,4 @@
add_library(commonengine python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp) add_library(commonengine v8/v8.cpp python/python2.cpp python/python3.cpp python/python.cpp pchooks/pchooks.cpp)
target_precompile_headers(commonengine REUSE_FROM pch) target_precompile_headers(commonengine REUSE_FROM pch)

220
LunaHook/engines/v8/v8.cpp Normal file
View File

@ -0,0 +1,220 @@
#include"types.h"
#include"main.h"
#include"v8.h"
#ifndef _WIN64
#define arg2 stack[2]
#else
#define arg2 rdx
#endif
namespace{
bool hookClipboard(){
HookParam hp;
hp.address=(uintptr_t)SetClipboardData;
hp.type= USING_STRING|CODEC_UTF16|EMBED_ABLE|EMBED_BEFORE_SIMPLE;
hp.text_fun=[](hook_stack* stack, HookParam *hp, uintptr_t* data, uintptr_t* split, size_t* len){
HGLOBAL hClipboardData=(HGLOBAL)stack->arg2;
*data=(uintptr_t)GlobalLock(hClipboardData);
*len=wcslen((wchar_t*)*data)*2;
GlobalUnlock(hClipboardData);
};
hp.hook_after=[](hook_stack*s,void* data, size_t len){
HGLOBAL hClipboardData = GlobalAlloc(GMEM_MOVEABLE, len +2);
auto pchData = (wchar_t*)GlobalLock(hClipboardData);
wcscpy(pchData, (wchar_t*)data);
GlobalUnlock(hClipboardData);
s->arg2=(uintptr_t)hClipboardData;
};
return NewHook(hp,"hookClipboard");
}
}
namespace v8script{
HMODULE hmodule;
#ifndef _WIN64
#define fnNewFromUtf8v2 "?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@2@H@Z"
#define fnNewFromUtf8v1 "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@12@H@Z"
#define fnGetCurrentContext "?GetCurrentContext@Isolate@v8@@QAE?AV?$Local@VContext@v8@@@2@XZ"
#define fnCompilev1 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Handle@VString@v8@@@2@PAVScriptOrigin@2@@Z"
#define fnCompilev12 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Local@VString@v8@@@2@PAVScriptOrigin@2@@Z"
#define fnRunv1 "?Run@Script@v8@@QAE?AV?$Local@VValue@v8@@@2@XZ"
#define fnCompilev2 "?Compile@Script@v8@@SA?AV?$MaybeLocal@VScript@v8@@@2@V?$Local@VContext@v8@@@2@V?$Local@VString@v8@@@2@PAVScriptOrigin@2@@Z"
#define fnRunv2 "?Run@Script@v8@@QAE?AV?$MaybeLocal@VValue@v8@@@2@V?$Local@VContext@v8@@@2@@Z"
typedef void*(__thiscall *GetCurrentContextt)(void*, void*);
typedef void*(__thiscall*Runt1)(void*,void*);
typedef void*(__thiscall*Runt2)(void*,void*,void*);
#else
#define fnNewFromUtf8v2 "?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@2@H@Z"
#define fnNewFromUtf8v1 "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@12@H@Z"
#define fnGetCurrentContext "?GetCurrentContext@Isolate@v8@@QEAA?AV?$Local@VContext@v8@@@2@XZ"
#define fnCompilev1 "?Compile@Script@v8@@SA?AV?$Local@VScript@v8@@@2@V?$Handle@VString@v8@@@2@PEAVScriptOrigin@2@@Z"
#define fnCompilev12 fnCompilev1
#define fnRunv1 "?Run@Script@v8@@QEAA?AV?$Local@VValue@v8@@@2@XZ"
#define fnCompilev2 "?Compile@Script@v8@@SA?AV?$MaybeLocal@VScript@v8@@@2@V?$Local@VContext@v8@@@2@V?$Local@VString@v8@@@2@PEAVScriptOrigin@2@@Z"
#define fnRunv2 "?Run@Script@v8@@QEAA?AV?$MaybeLocal@VValue@v8@@@2@V?$Local@VContext@v8@@@2@@Z"
typedef void*(*GetCurrentContextt)(void*, void*);
typedef void*(*Runt1)(void*,void*);
typedef void*(*Runt2)(void*,void*,void*);
#endif
typedef void*(*NewFromUtf8t)(void*, void*, const char*, int, int) ;
typedef void*(*Compilet)(void*, void*, void*, void*);
bool v8runscript_isolate(void* isolate){
if(isolate==0)return false;
NewFromUtf8t NewFromUtf8=0;
GetCurrentContextt GetCurrentContext ;
Compilet Compile;
void* Run;
auto NewFromUtf8v2 = (decltype(NewFromUtf8))GetProcAddress(hmodule, fnNewFromUtf8v2);
auto NewFromUtf8v1 = (decltype(NewFromUtf8))GetProcAddress(hmodule, fnNewFromUtf8v1);
GetCurrentContext = (decltype(GetCurrentContext))GetProcAddress(hmodule, fnGetCurrentContext);
if(NewFromUtf8v1)
{
NewFromUtf8=NewFromUtf8v1;
Compile = (decltype(Compile))GetProcAddress(hmodule, fnCompilev1);
if(!Compile) Compile=(decltype(Compile))GetProcAddress(hmodule, fnCompilev12);
Run = (decltype(Run))GetProcAddress(hmodule, fnRunv1);
}
else if(NewFromUtf8v2)
{
NewFromUtf8=NewFromUtf8v2;
Compile = (decltype(Compile))GetProcAddress(hmodule, fnCompilev2);
Run = (decltype(Run))GetProcAddress(hmodule, fnRunv2);
}
ConsoleOutput("%p %p",NewFromUtf8v1,NewFromUtf8v2);
ConsoleOutput("%p %p %p %p",GetCurrentContext, NewFromUtf8, Compile, Run);
if(!(GetCurrentContext && NewFromUtf8 && Compile && Run))return false;
void* context;
void* v8string;
void* script;
void* useless;
ConsoleOutput("isolate %p",isolate);
GetCurrentContext(isolate,&context);
ConsoleOutput("context %p",context);
if(context==0)return false;
NewFromUtf8(&v8string,isolate,LoadResData(L"lunajspatch",L"JSSOURCE").c_str(),1,-1);
ConsoleOutput("v8string %p",v8string);
if(v8string==0)return false;
if(NewFromUtf8v1)
{
Compile(&script,v8string,0,0);
ConsoleOutput("script %p",script);
if(script==0)return false;
((Runt1)Run)(script,&useless);
}
else if(NewFromUtf8v2)
{
Compile(&script,context,v8string,0);
ConsoleOutput("script %p",script);
if(script==0)return false;
((Runt2)Run)(script,&useless,context);
ConsoleOutput("useless %p",useless);
}
return true;
}
void v8runscript_isolate_bypass(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
hp->type=HOOK_EMPTY;hp->text_fun=nullptr;
#ifndef _WIN64
#define isolatearg stack[2]
#else
#define isolatearg rdx
#endif
auto isolate=(void*)stack->isolatearg;//测试正确且和v8::Isolate::GetCurrent结果相同
v8runscript_isolate(isolate);
}
void* v8getcurrisolate(HMODULE hmod){
#ifndef _WIN64
#define fnGetCurrent "?GetCurrent@Isolate@v8@@SAPAV12@XZ"
#define fnTryGetCurrent "?TryGetCurrent@Isolate@v8@@SAPAV12@XZ"
#else
#define fnGetCurrent "?GetCurrent@Isolate@v8@@SAPEAV12@XZ"
#define fnTryGetCurrent "?TryGetCurrent@Isolate@v8@@SAPEAV12@XZ"
#endif
void* GetCurrent;
GetCurrent = GetProcAddress(hmod, fnGetCurrent);
if ( !GetCurrent )
GetCurrent = GetProcAddress(hmod, fnTryGetCurrent);
if(!GetCurrent)return 0;
auto isolate=((void*(*)())GetCurrent)();
return isolate;
}
bool v8runscript(HMODULE _hmodule){
auto isolate=v8getcurrisolate(_hmodule);
if(isolate)
return v8runscript_isolate(isolate);
#ifndef _WIN64
#define isolategetter "?NewFromUtf8@String@v8@@SA?AV?$Local@VString@v8@@@2@PAVIsolate@2@PBDW4NewStringType@12@H@Z"
#else
#define isolategetter "?Utf8Length@String@v8@@QEBAHPEAVIsolate@2@@Z" //旧版没有
//??0TryCatch@v8@@QEAA@PEAVIsolate@1@@Z也可以但是有报错
#endif
auto stringlengthisolate=GetProcAddress(_hmodule,isolategetter);
if(!stringlengthisolate)return false;
hmodule=_hmodule;
HookParam hp;
hp.address=(uintptr_t)stringlengthisolate;
hp.text_fun=v8runscript_isolate_bypass;
return NewHook(hp,"v8isolate");
}
}
namespace{
bool hookstringlength(HMODULE hm){
#ifndef _WIN64
#define v8StringLength "?Length@String@v8@@QBEHXZ"
#define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QBEHPADHPAHH@Z"
#define v8StringUtf8Length "?Utf8Length@String@v8@@QBEHXZ"
#else
#define v8StringLength "?Length@String@v8@@QEBAHXZ"
#define v8StringWriteUtf8 "?WriteUtf8@String@v8@@QEBAHPEADHPEAHH@Z"
#define v8StringUtf8Length "?Utf8Length@String@v8@@QEBAHXZ"
#endif
auto Length=GetProcAddress(hm,v8StringLength);
static uintptr_t WriteUtf8;
static uintptr_t Utf8Length;
WriteUtf8=(uintptr_t)GetProcAddress(hm,v8StringWriteUtf8);
Utf8Length=(uintptr_t)GetProcAddress(hm,v8StringUtf8Length);
if(Length==0||WriteUtf8==0||Utf8Length==0)return false;
HookParam hp;
hp.address=(uintptr_t)Length;
hp.type=USING_STRING|CODEC_UTF8;
hp.text_fun=
[](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
{
#ifndef _WIN64
auto length=((size_t(__thiscall*)(void*))Utf8Length)((void*)stack->ecx);
#else
auto length=((size_t(*)(void*))Utf8Length)((void*)stack->rcx);
#endif
if(!length)return;
auto u8str=new char[length+1];
int writen;
#ifndef _WIN64
((size_t(__thiscall*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->ecx,u8str,length,&writen,0);
#else
((size_t(*)(void*,char*,int,int*,int))WriteUtf8)((void*)stack->rcx,u8str,length,&writen,0);
#endif
*data=(uintptr_t)u8str;
*len=length;
};
return NewHook(hp,"v8::String::Length");
}
}
bool tryhookv8(HMODULE hm){
auto succ=hookstringlength(hm);
if(v8script::v8runscript(hm))
succ|= hookClipboard();
return succ;
}

2
LunaHook/engines/v8/v8.h Normal file
View File

@ -0,0 +1,2 @@
bool tryhookv8(HMODULE hm);

View File

@ -6,4 +6,6 @@ compound_chars_Robotics_Notes_Elite COMPOUND_CHARS "resource/compound_chars_Robo
compound_chars_Robotics_Notes_Dash COMPOUND_CHARS "resource/compound_chars_Robotics_Notes_Dash.txt" compound_chars_Robotics_Notes_Dash COMPOUND_CHARS "resource/compound_chars_Robotics_Notes_Dash.txt"
renpy_hook_font PYSOURCE "resource/renpy_hook_font.py" renpy_hook_font PYSOURCE "resource/renpy_hook_font.py"
renpy_hook_text PYSOURCE "resource/renpy_hook_text.py" renpy_hook_text PYSOURCE "resource/renpy_hook_text.py"
lunajspatch JSSOURCE "resource/lunajspatch.js"

View File

@ -0,0 +1,47 @@
function NWjshook(){
function NWjssend(s) {
const _clipboard = require('nw.gui').Clipboard.get();
_clipboard.set(s, 'text');
return _clipboard.get('text')
}
if(Window_Message.prototype.originstartMessage)return;
Window_Message.prototype.originstartMessage=Window_Message.prototype.startMessage;
Window_Message.prototype.startMessage = function()
{
gametext = $gameMessage.allText();
resp=NWjssend(gametext);
$gameMessage._texts=[resp]
this.originstartMessage();
};
}
function Electronhook() {
function Electronsend(s) {
const { clipboard } = require('electron');
clipboard.writeText(s);
return clipboard.readText();
}
if(tyrano.plugin.kag.tag.text.originshowMessage)return;
tyrano.plugin.kag.tag.text.originshowMessage=tyrano.plugin.kag.tag.text.showMessage;
tyrano.plugin.kag.tag.text.showMessage = function () {
arguments[0]=Electronsend(arguments[0]);
return tyrano.plugin.kag.tag.text.originshowMessage.apply(this, arguments);
}
}
function retryinject(times){
if(times==0)return;
if(window.tyrano && tyrano.plugin){
Electronhook();
}
else if(window.Utils && Utils.RPGMAKER_NAME){
NWjshook();
}
else{
setTimeout(retryinject,3000,times-1);
}
}
setTimeout(retryinject,3000,3);