Skip to content

Commit d38ca1f

Browse files
committed
fix: fix old nodejs addon load error #9
1 parent 1fc0773 commit d38ca1f

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

src/legacy/main/NodeJsHelper.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,26 @@
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+
2330
using ll::chrono_literals::operator""_tick;
2431

2532
// pre-declare
@@ -38,7 +45,81 @@ std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmen
3845
std::unordered_map<node::Environment*, bool> isRunning;
3946
std::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+
41119
bool 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();

src/lse/Config.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
#pragma once
22

3+
#include <optional>
4+
35
namespace lse {
46

57
struct Config {
68
int version = 1;
79
bool migratePlugins = true;
10+
#ifdef LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
11+
std::optional<bool> fixOldAddon{std::nullopt};
12+
#endif
813
};
914

1015
} // namespace lse

0 commit comments

Comments
 (0)