77#include " engine/EngineOwnData.h"
88#include " engine/RemoteCall.h"
99#include " fmt/format.h"
10+ #include " ll/api/Expected.h"
11+ #include " ll/api/base/Containers.h"
1012#include " ll/api/chrono/GameChrono.h"
1113#include " ll/api/coro/CoroTask.h"
1214#include " ll/api/io/FileUtils.h"
1315#include " ll/api/io/LogLevel.h"
16+ #include " ll/api/memory/Hook.h"
1417#include " ll/api/service/GamingStatus.h"
1518#include " ll/api/service/ServerInfo.h"
1619#include " ll/api/thread/ServerThreadExecutor.h"
1720#include " ll/api/utils/StringUtils.h"
21+ #include " lse/Entry.h"
1822#include " main/Global.h"
1923#include " utils/Utils.h"
2024#include " uv/uv.h"
2125#include " v8/v8.h"
2226
27+ #define NODE_LIBRARY_NAME_W L" libnode.dll"
28+ #define NODE_HOST_BINARY_NAME " node.exe"
29+
2330using ll::chrono_literals::operator " " _tick;
2431
2532// pre-declare
@@ -38,7 +45,81 @@ std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmen
3845std::unordered_map<node::Environment*, bool > isRunning;
3946std::vector<node::Environment*> uvLoopTask;
4047
48+ ll::Expected<> PatchDelayImport (HMODULE hAddon, HMODULE hLibNode) {
49+ BYTE* base = (BYTE*)hAddon;
50+ auto dos = (PIMAGE_DOS_HEADER)base;
51+ if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
52+ return ll::makeStringError (" Invalid DOS signature." );
53+ }
54+ auto nt = (PIMAGE_NT_HEADERS)(base + dos->e_lfanew );
55+ if (nt->Signature != IMAGE_NT_SIGNATURE) {
56+ return ll::makeStringError (" Invalid NT signature." );
57+ }
58+ DWORD rva = nt->OptionalHeader .DataDirectory [IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress ;
59+ if (!rva) {};
60+ auto pDesc = (PIMAGE_DELAYLOAD_DESCRIPTOR)(base + rva);
61+ for (; pDesc->DllNameRVA ; ++pDesc) {
62+ char * szDll = (char *)(base + pDesc->DllNameRVA );
63+ if (_stricmp (szDll, NODE_HOST_BINARY_NAME) != 0 ) continue ;
64+
65+ auto pIAT = (PIMAGE_THUNK_DATA)(base + pDesc->ImportAddressTableRVA );
66+ auto pINT = (PIMAGE_THUNK_DATA)(base + pDesc->ImportNameTableRVA );
67+
68+ for (; pIAT->u1 .Function ; ++pIAT, ++pINT) {
69+ FARPROC f = nullptr ;
70+ if (pINT->u1 .Ordinal & IMAGE_ORDINAL_FLAG) {
71+ // Import by Ordinal
72+ WORD ordinal = IMAGE_ORDINAL (pINT->u1 .Ordinal );
73+ f = GetProcAddress (hLibNode, MAKEINTRESOURCEA (ordinal));
74+ } else {
75+ // Import by name
76+ auto name = (PIMAGE_IMPORT_BY_NAME)(base + pINT->u1 .AddressOfData );
77+ f = GetProcAddress (hLibNode, name->Name );
78+ }
79+ if (f) {
80+ DWORD oldProt;
81+ VirtualProtect (&pIAT->u1 .Function , sizeof (void *), PAGE_READWRITE, &oldProt);
82+ pIAT->u1 .Function = reinterpret_cast <decltype (pIAT->u1 .Function )>(f);
83+ VirtualProtect (&pIAT->u1 .Function , sizeof (void *), oldProt, &oldProt);
84+ }
85+ }
86+ break ;
87+ }
88+ return {};
89+ }
90+
91+ ll::DenseSet<HMODULE> cachedModules{};
92+
93+ // patch in node?
94+ LL_STATIC_HOOK (
95+ PatchDelayImportHook,
96+ HookPriority::Normal,
97+ LoadLibraryExW,
98+ HMODULE,
99+ LPCWSTR lpLibFileName,
100+ HANDLE hFile,
101+ DWORD dwFlags
102+ ) {
103+ auto hAddon = origin (lpLibFileName, hFile, dwFlags);
104+ if (!cachedModules.contains (hAddon)) {
105+ cachedModules.emplace (hAddon);
106+ if (std::wstring_view (lpLibFileName).ends_with (L" .node" )) {
107+ static HMODULE hLibNode = GetModuleHandle (NODE_LIBRARY_NAME_W);
108+ if (!(hAddon && hLibNode)) return hAddon;
109+ auto res = PatchDelayImport (hAddon, hLibNode);
110+ if (res) return hAddon;
111+ res.error ().log (lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ());
112+ }
113+ }
114+ return hAddon;
115+ }
116+
117+ std::unique_ptr<ll::memory::HookRegistrar<PatchDelayImportHook>> hook{};
118+
41119bool initNodeJs () {
120+ if (lse::LegacyScriptEngine::getInstance ().getConfig ().fixOldAddon .value_or (true )) {
121+ hook = std::make_unique<ll::memory::HookRegistrar<PatchDelayImportHook>>();
122+ }
42123 // Init NodeJs
43124 auto path = ll::string_utils::u8str2str (ll::sys_utils::getModulePath (nullptr ).value ().u8string ());
44125 char * cPath = (char *)path.c_str ();
0 commit comments