This commit is contained in:
恍兮惚兮 2024-10-20 14:07:21 +08:00
parent b79bda0f1f
commit ea03dc7dd6
4 changed files with 153 additions and 135 deletions

View File

@ -62,7 +62,7 @@ include(generate_product_version)
set(VERSION_MAJOR 3)
set(VERSION_MINOR 15)
set(VERSION_PATCH 0)
set(VERSION_PATCH 1)
set(VERSION_REVISION 0)
if(BUILD_CORE)

View File

@ -471,29 +471,6 @@ Return Value:
--***************************************************************************/
std::string urlDecode(const std::string &encoded)
{
std::string decoded;
for (size_t i = 0; i < encoded.size(); i++)
{
if (encoded[i] == '%')
{
char ch = std::stoi(encoded.substr(i + 1, 2), 0, 16);
decoded += ch;
i = i + 2;
}
else if (encoded[i] == '+')
{
decoded += ' ';
}
else
{
decoded += encoded[i];
}
}
return decoded;
}
#pragma optimize("", off)
const wchar_t *LUNA_CONTENTBYPASS(const wchar_t *_)
{
@ -507,57 +484,114 @@ SendHttpResponse(
IN PHTTP_REQUEST pRequest)
{
HTTP_RESPONSE response;
HTTP_DATA_CHUNK dataChunk;
DWORD result;
DWORD bytesSent;
USHORT StatusCode = 200;
PSTR pReason = "OK";
ULONG BytesRead;
HTTP_DATA_CHUNK dataChunk;
std::string recv;
std::string buff;
buff.resize(2048);
bool recving = true;
//
// Initialize the HTTP response structure.
//
INITIALIZE_HTTP_RESPONSE(&response, StatusCode, pReason);
INITIALIZE_HTTP_RESPONSE(&response, 200, "OK");
//
// Add a known header.
// For POST, we'll echo back the entity that we got from the client.
//
ADD_KNOWN_HEADER(response, HttpHeaderContentType, "text/html");
std::string url(pRequest->pRawUrl, pRequest->RawUrlLength);
auto fnd = url.find('?');
if (fnd != url.npos)
// NOTE: If we had passed the HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY
// flag with HttpReceiveHttpRequest(), the entity would have
// been a part of HTTP_REQUEST (using the pEntityChunks field).
// Since we have not passed that flag, we can be assured that
// there are no entity bodies in HTTP_REQUEST.
//
if (pRequest->Flags & HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS)
{
url = url.substr(fnd + 1);
url = urlDecode(url);
url = WideStringToString(LUNA_CONTENTBYPASS(StringToWideString(url).c_str()));
// The entity body is send over multiple calls. Let's collect all
// of these in a file & send it back. We'll create a temp file
//
// Add an entity chunk
//
dataChunk.DataChunkType = HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer = (PVOID)url.c_str();
dataChunk.FromMemory.BufferLength = (ULONG)url.size();
response.EntityChunkCount = 1;
response.pEntityChunks = &dataChunk;
do
{
//
// Read the entity chunk from the request.
//
BytesRead = 0;
result = HttpReceiveRequestEntityBody(
hReqQueue,
pRequest->RequestId,
0,
buff.data(),
buff.capacity(),
&BytesRead,
NULL);
switch (result)
{
case NO_ERROR:
case ERROR_HANDLE_EOF:
if (BytesRead != 0)
{
recv += buff.substr(0, BytesRead);
}
if (result == ERROR_HANDLE_EOF)
recving = false;
break;
default:
recving = false;
}
} while (recving);
}
if (recv.size())
recv = WideStringToString(LUNA_CONTENTBYPASS(StringToWideString(recv).c_str()));
if (recv.size())
{
ADD_KNOWN_HEADER(
response,
HttpHeaderContentLength,
std::to_string(recv.size()).c_str());
}
result =
HttpSendHttpResponse(
hReqQueue, // ReqQueueHandle
pRequest->RequestId, // Request ID
recv.size() ? HTTP_SEND_RESPONSE_FLAG_MORE_DATA : 0,
&response, // HTTP response
NULL, // pReserved1
&bytesSent, // bytes sent (optional)
NULL, // pReserved2
0, // Reserved3
NULL, // LPOVERLAPPED
NULL // pReserved4
);
if (result != NO_ERROR)
{
return result;
}
if (!recv.size())
return result;
//
// Since we are sending all the entity body in one call, we don't have
// to specify the Content-Length.
// Send entity body from a file handle.
//
dataChunk.DataChunkType = HttpDataChunkFromMemory;
dataChunk.FromMemory.pBuffer = (PVOID)recv.c_str();
dataChunk.FromMemory.BufferLength = (ULONG)recv.size();
result = HttpSendHttpResponse(
hReqQueue, // ReqQueueHandle
pRequest->RequestId, // Request ID
0, // Flags
&response, // HTTP response
NULL, // pReserved1
&bytesSent, // bytes sent (OPTIONAL)
NULL, // pReserved2 (must be NULL)
0, // Reserved3 (must be 0)
NULL, // LPOVERLAPPED (OPTIONAL)
NULL // pReserved4 (must be NULL)
);
result = HttpSendResponseEntityBody(
hReqQueue,
pRequest->RequestId,
0, // This is the last send.
1, // Entity Chunk Count.
&dataChunk,
NULL,
NULL,
0,
NULL,
NULL);
return result;
}

View File

@ -8,6 +8,12 @@ namespace
constexpr auto magicrecv = L"\x01LUNAFROMHOST\x01";
}
namespace
{
bool useclipboard = true;
bool usehttp = true;
int usehttp_port = 0;
}
namespace
{
void parsebefore(wchar_t *text, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
@ -150,25 +156,11 @@ namespace v8script
}
}
}
auto port = 0;
auto useclipboard = !std::filesystem::exists(std::filesystem::path(getModuleFilename().value()).replace_filename("disable.clipboard"));
auto usehttp = !std::filesystem::exists(std::filesystem::path(getModuleFilename().value()).replace_filename("disable.http"));
if (usehttp)
{
port = makehttpgetserverinternal();
ConsoleOutput("%d %d", GetCurrentProcessId(), port);
hook_LUNA_CONTENTBYPASS();
dont_detach = true;
}
if (useclipboard)
{
hookClipboard();
}
auto lunajspatch = LoadResData(L"lunajspatch", L"JSSOURCE");
strReplace(lunajspatch, "IS_PACKED", std::to_string(is_packed));
strReplace(lunajspatch, "IS_USECLIPBOARD", std::to_string(useclipboard));
strReplace(lunajspatch, "INTERNAL_HTTP_PORT", std::to_string(port));
strReplace(lunajspatch, "INTERNAL_HTTP_PORT", std::to_string(usehttp_port));
NewFromUtf8(&v8string, isolate, lunajspatch.c_str(), 1, -1);
ConsoleOutput("v8string %p", v8string);
if (v8string == 0)
@ -363,10 +355,24 @@ bool tryhookv8()
auto hm = GetModuleHandleW(moduleName);
if (hm == 0)
continue;
auto ok = hookstring(hm);
ok |= v8script::v8runscript(hm);
if (ok)
return true;
if (hookstring(hm))
{
useclipboard = !std::filesystem::exists(std::filesystem::path(getModuleFilename().value()).replace_filename("disable.clipboard"));
usehttp = !std::filesystem::exists(std::filesystem::path(getModuleFilename().value()).replace_filename("disable.http"));
if (usehttp)
{
usehttp_port = makehttpgetserverinternal();
ConsoleOutput("%d %d", GetCurrentProcessId(), usehttp_port);
hook_LUNA_CONTENTBYPASS();
dont_detach = true;
}
if (useclipboard)
{
hookClipboard();
}
return v8script::v8runscript(hm);
}
}
return false;
}

View File

@ -12,7 +12,6 @@ function splitfonttext(transwithfont) {
}
else if (transwithfont.substr(0, magicrecv.length) == magicrecv) {
transwithfont = transwithfont.substr(magicrecv.length)
//magic font \x02 text
split = transwithfont.search('\x02')
fontface = transwithfont.substr(0, split)
text = transwithfont.substr(split + 1)
@ -22,61 +21,40 @@ function splitfonttext(transwithfont) {
return transwithfont;
}
}
function syncquery(s) {
if (internal_http_port == 0) { throw new Error('') }
var xhr = new XMLHttpRequest();
var url = 'http://127.0.0.1:' + internal_http_port + '/fuck?' + s
xhr.open('GET', url, false);
xhr.send();
if (xhr.status === 200) {
return xhr.responseText;//解析这个会导致v8::String::Length的v8StringUtf8Length出现错误但不影响。
} else {
throw new Error('')
}
}
function makecomplexs(name, s_raw, lpsplit) {
return magicsend + name + '\x03' + lpsplit.toString() + '\x02' + s_raw;
}
function cppjsio(s) {
try {
return syncquery(s)
}
catch (err) {
try {
if (!is_useclipboard) { throw new Error('') }
const _clipboard = require('nw.gui').Clipboard.get();
_clipboard.set(s, 'text');
return _clipboard.get('text');
}
catch (err2) {
try {
if (!is_useclipboard) { throw new Error('') }
const clipboard = require('electron').clipboard;
clipboard.writeText(s);
return clipboard.readText();
}
catch (err3) {
return s_raw;
}
}
}
}
function clipboardsender(name, s_raw, lpsplit) {
//magic split \x02 text
function cppjsio(name, s_raw, lpsplit) {
if (!s_raw)
return s_raw
transwithfont = cppjsio(makecomplexs(name, s_raw, lpsplit))
if (transwithfont.length == 0) return s_raw;
transwithfont = ''
s = magicsend + name + '\x03' + lpsplit.toString() + '\x02' + s_raw;
if (internal_http_port) {
var xhr = new XMLHttpRequest();
var url = 'http://127.0.0.1:' + internal_http_port + '/fuck'
xhr.open('POST', url, false);
xhr.send(s);
if (xhr.status === 200) {
transwithfont = xhr.responseText;
}
}
else if (is_useclipboard) {
try {
const _clipboard = require('nw.gui').Clipboard.get();
_clipboard.set(s, 'text');
transwithfont = _clipboard.get('text');
}
catch (err) {
try {
const clipboard = require('electron').clipboard;
clipboard.writeText(s);
transwithfont = clipboard.readText();
}
catch (err2) {
}
}
}
if (!transwithfont) return s_raw;
return splitfonttext(transwithfont)
}
function clipboardsender_only_send(name, s_raw, lpsplit) {
//magic split \x02 text
if (!s_raw)
return s_raw
cppjsio(makecomplexs(name, s_raw, lpsplit))
}
function rpgmakerhook() {
if (Window_Message.prototype.originstartMessage) { }
@ -99,7 +77,7 @@ function rpgmakerhook() {
setInterval(function () {
for (lpsplit in Bitmap.prototype.collectstring) {
if (Bitmap.prototype.collectstring[lpsplit].length) {
clipboardsender_only_send('rpgmakermv', Bitmap.prototype.collectstring[lpsplit], lpsplit)
cppjsio('rpgmakermv', Bitmap.prototype.collectstring[lpsplit], lpsplit)
Bitmap.prototype.collectstring[lpsplit] = ''
}
}
@ -121,12 +99,12 @@ function rpgmakerhook() {
}
Window_Message.prototype.startMessage = function () {
gametext = $gameMessage.allText();
resp = clipboardsender('rpgmakermv', gametext, 0);
resp = cppjsio('rpgmakermv', gametext, 0);
$gameMessage._texts = [resp]
this.originstartMessage();
};
Window_Base.prototype.drawText = function (text, x, y, maxWidth, align) {
text = clipboardsender('rpgmakermv', text, 1)
text = cppjsio('rpgmakermv', text, 1)
return this.drawText_origin(text, x, y, maxWidth, align)
}
Window_Base.prototype.lastcalltime = 0
@ -135,7 +113,7 @@ function rpgmakerhook() {
__now = new Date().getTime()
Window_Base.prototype.lastcalltime = __now
if (__now - __last > 100)
text = clipboardsender('rpgmakermv', text, 2)
text = cppjsio('rpgmakermv', text, 2)
else {
Bitmap.prototype.collectstring[2] += text;
}
@ -150,7 +128,7 @@ function tyranohook() {
tyrano.plugin.kag.tag.chara_ptext.startorigin = tyrano.plugin.kag.tag.chara_ptext.start;
tyrano.plugin.kag.tag.text.start = function (pm) {
if (1 != this.kag.stat.is_script && 1 != this.kag.stat.is_html) {
pm.val = clipboardsender('tyranoscript', pm.val, 0);
pm.val = cppjsio('tyranoscript', pm.val, 0);
if (fontface) {
this.kag.stat.font.face = fontface
}
@ -158,7 +136,7 @@ function tyranohook() {
return this.originstart(pm)
}
tyrano.plugin.kag.tag.chara_ptext.start = function (pm) {
pm.name = clipboardsender('tyranoscript', pm.name, 1)
pm.name = cppjsio('tyranoscript', pm.name, 1)
return this.startorigin(pm)
}
}