mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-30 23:14:12 +08:00
207 lines
8.5 KiB
C++
207 lines
8.5 KiB
C++
#include"types.h"
|
||
#include"embed_util.h"
|
||
#include"main.h"
|
||
namespace {
|
||
typedef wchar_t Py_UNICODE ;
|
||
typedef size_t Py_ssize_t;
|
||
typedef void PyObject ;
|
||
typedef PyObject* (*PyUnicode_FromObject_t)( PyObject *obj );
|
||
#ifdef Py_TRACE_REFS
|
||
/* Define pointers to support a doubly-linked list of all live heap objects. */
|
||
#define _PyObject_HEAD_EXTRA \
|
||
struct _object *_ob_next; \
|
||
struct _object *_ob_prev;
|
||
|
||
#define _PyObject_EXTRA_INIT 0, 0,
|
||
|
||
#else
|
||
#define _PyObject_HEAD_EXTRA
|
||
#define _PyObject_EXTRA_INIT
|
||
#endif
|
||
#define PyObject_HEAD \
|
||
_PyObject_HEAD_EXTRA \
|
||
Py_ssize_t ob_refcnt; \
|
||
struct _typeobject *ob_type;
|
||
typedef struct {
|
||
PyObject_HEAD
|
||
Py_ssize_t length; /* Length of raw Unicode data in buffer */
|
||
Py_UNICODE *str; /* Raw Unicode buffer */
|
||
long hash; /* Hash value; -1 if not set */
|
||
PyObject *defenc; /* (Default) Encoded version as Python
|
||
string, or NULL; this is used for
|
||
implementing the buffer protocol */
|
||
} PyUnicodeObject;
|
||
#define PyUnicode_AS_UNICODE(op) \
|
||
(((PyUnicodeObject *)(op))->str)
|
||
#define PyUnicode_GET_SIZE(op) \
|
||
(((PyUnicodeObject *)(op))->length)
|
||
|
||
PyUnicode_FromObject_t PyUnicode_FromObject;
|
||
|
||
inline std::pair<Py_UNICODE*,Py_ssize_t> GetPyUnicodeString(PyObject *object){
|
||
if(PyUnicode_FromObject==NULL)
|
||
return {};
|
||
if (object == NULL)
|
||
return {};
|
||
|
||
auto uformat = PyUnicode_FromObject(object);
|
||
|
||
if (uformat == NULL){
|
||
return {};
|
||
}
|
||
|
||
auto fmt = PyUnicode_AS_UNICODE(uformat);
|
||
auto fmtcnt = PyUnicode_GET_SIZE(uformat);
|
||
return {fmt,fmtcnt};
|
||
}
|
||
|
||
typedef PyObject* (*PyUnicode_FromUnicode_t)(
|
||
const Py_UNICODE *u, /* Unicode buffer */
|
||
Py_ssize_t size /* size of buffer */
|
||
);
|
||
PyUnicode_FromUnicode_t PyUnicode_FromUnicode;
|
||
|
||
typedef enum {PyGILState_LOCKED, PyGILState_UNLOCKED}
|
||
PyGILState_STATE;
|
||
typedef PyGILState_STATE (*PyGILState_Ensure_t)(void);
|
||
PyGILState_Ensure_t PyGILState_Ensure;
|
||
typedef void (*PyGILState_Release_t)(PyGILState_STATE);
|
||
PyGILState_Release_t PyGILState_Release;
|
||
typedef int (*PyRun_SimpleString_t)(const char *command);
|
||
PyRun_SimpleString_t PyRun_SimpleString;
|
||
}
|
||
|
||
bool InsertRenpyHook(){
|
||
wchar_t python[] = L"python2X.dll", libpython[] = L"libpython2.X.dll";
|
||
for (wchar_t* name : { python, libpython })
|
||
{
|
||
wchar_t* pos = wcschr(name, L'X');
|
||
for (int pythonMinorVersion = 0; pythonMinorVersion <= 8; ++pythonMinorVersion)
|
||
{
|
||
*pos = L'0' + pythonMinorVersion;
|
||
if (HMODULE module = GetModuleHandleW(name))
|
||
{
|
||
PyUnicode_FromObject=(PyUnicode_FromObject_t)GetProcAddress(module, "PyUnicodeUCS2_FromObject");
|
||
PyUnicode_FromUnicode=(PyUnicode_FromUnicode_t)GetProcAddress(module, "PyUnicodeUCS2_FromUnicode");
|
||
auto f1=[=](){
|
||
HookParam hp;
|
||
hp.address = (uintptr_t)GetProcAddress(module, "PyUnicodeUCS2_Format");
|
||
if (!hp.address) return false;
|
||
|
||
hp.text_fun = [](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
|
||
{
|
||
#ifndef _WIN64
|
||
auto format=(PyObject *)stack->stack[1];
|
||
#else
|
||
auto format=(PyObject *)stack->rcx;
|
||
#endif
|
||
auto [strptr,strlen]=GetPyUnicodeString(format);
|
||
*data=(uintptr_t)strptr;
|
||
*len=0;
|
||
|
||
if(wcschr(strptr, L'%') == nullptr)
|
||
*len=sizeof(wchar_t)*strlen;
|
||
|
||
};
|
||
hp.type = USING_STRING | CODEC_UTF16 | NO_CONTEXT;
|
||
if(PyUnicode_FromUnicode)
|
||
{
|
||
hp.type|=EMBED_ABLE|EMBED_BEFORE_SIMPLE;
|
||
hp.hook_after=[](hook_stack* stack,void* data, size_t len)
|
||
{
|
||
#ifndef _WIN64
|
||
auto format=(PyObject *)stack->stack[1];
|
||
#else
|
||
auto format=(PyObject *)stack->rcx;
|
||
#endif
|
||
if(format==NULL)return;
|
||
#ifndef _WIN64
|
||
stack->stack[1]=
|
||
#else
|
||
stack->rcx=
|
||
#endif
|
||
(uintptr_t)PyUnicode_FromUnicode((Py_UNICODE *)data,len/2);
|
||
};
|
||
PyGILState_Ensure=(PyGILState_Ensure_t)GetProcAddress(module, "PyGILState_Ensure");
|
||
PyGILState_Release=(PyGILState_Release_t)GetProcAddress(module, "PyGILState_Release");
|
||
PyRun_SimpleString=(PyRun_SimpleString_t)GetProcAddress(module, "PyRun_SimpleString");
|
||
patch_fun=[](){
|
||
//由于不知道怎么从字体名映射到ttc/ttf文件名,所以暂时写死arial/msyh
|
||
if(wcslen(embedsharedmem->fontFamily)==0)return;
|
||
auto state=PyGILState_Ensure();
|
||
PyRun_SimpleString(
|
||
R"(
|
||
try:
|
||
import renpy
|
||
import ctypes
|
||
import os
|
||
def hook_renpy_text_font_get_font_init(original):
|
||
def new_init(*args, **kwargs):
|
||
#ctypes.windll.user32.MessageBoxW(None, str(kwargs), str(args), 0)
|
||
if os.path.exists(r'C:\Windows\Fonts\msyh.ttc'):
|
||
font='msyh.ttc'
|
||
elif os.path.exists(r'C:\Windows\Fonts\arial.ttf'):
|
||
font='arial.ttf'
|
||
else:
|
||
font=None
|
||
if font:
|
||
args=(font,)+args[1:]
|
||
if 'fn' in kwargs:
|
||
kwargs['fn']=font
|
||
return original(*args, **kwargs)
|
||
|
||
return new_init
|
||
renpy.text.font.get_font = hook_renpy_text_font_get_font_init(renpy.text.font.get_font)
|
||
except:
|
||
pass
|
||
)");
|
||
PyGILState_Release(state);
|
||
};
|
||
}
|
||
return NewHook(hp, "Ren'py");
|
||
}();
|
||
|
||
#ifndef _WIN64
|
||
auto f2=[=](){
|
||
HookParam hp;
|
||
hp.address = (uintptr_t)GetProcAddress(module, "PyUnicodeUCS2_Concat");
|
||
if (!hp.address) return false;
|
||
hp.text_fun = [](hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len)
|
||
{
|
||
auto left=(PyObject *)stack->stack[1];
|
||
auto right=(PyObject *)stack->stack[2];
|
||
|
||
auto [strptr,strlen]=GetPyUnicodeString(right);
|
||
*data=(uintptr_t)strptr;
|
||
*len=sizeof(wchar_t)*strlen;
|
||
};
|
||
hp.filter_fun = [](void* data, size_t* len, HookParam* hp)
|
||
{
|
||
auto str=std::wstring(reinterpret_cast<LPWSTR>(data),*len/2);
|
||
auto filterpath={
|
||
L".rpy",L".rpa",L".py",L".pyc",L".txt",
|
||
L".png",L".jpg",L".bmp",
|
||
L".mp3",L".ogg",
|
||
L".webm",L".mp4",
|
||
L".otf",L".ttf"
|
||
};
|
||
for(auto _ :filterpath)
|
||
if(str.find(_)!=str.npos)
|
||
return false;
|
||
return true;
|
||
};
|
||
hp.type = USING_STRING | CODEC_UTF16;
|
||
//hp.filter_fun = [](void* str, auto, auto, auto) { return *(wchar_t*)str != L'%'; };
|
||
return NewHook(hp, "Ren'py");
|
||
}();
|
||
#else
|
||
auto f2=false;
|
||
#endif
|
||
return f1||f2;
|
||
}
|
||
}
|
||
}
|
||
ConsoleOutput("Ren'py failed: failed to find python2X.dll");
|
||
return false;
|
||
}
|
||
|