Skip to content

Commit

Permalink
hook main directly, instead of hook __scrt_common_main_seh
Browse files Browse the repository at this point in the history
  • Loading branch information
karikera committed Mar 11, 2021
1 parent 5b890d5 commit b83ffaa
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 79 deletions.
1 change: 1 addition & 0 deletions bdsx/bdsx.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ echo #define BUILD_TIME "%25date%-%time2:.=%"&gt;"gen/buildtime.h"</Command>
</ItemGroup>
<ItemGroup>
<ClInclude Include="mtqueue.h" />
<ClInclude Include="unwind.h" />
<ClInclude Include="uvasync.h" />
<ClInclude Include="structurepointer.h" />
<ClInclude Include="cachedpdb.h" />
Expand Down
1 change: 1 addition & 0 deletions bdsx/bdsx.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<ClInclude Include="uvasync.h" />
<ClInclude Include="staticpointer.h" />
<ClInclude Include="mtqueue.h" />
<ClInclude Include="unwind.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="src">
Expand Down
5 changes: 0 additions & 5 deletions bdsx/cachedpdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,6 @@ JsValue CachedPdb::getProcAddresses(pcstr16 predefined, JsValue out, JsValue arr
}
if (!local.quiet)
{
line << hexf((byte*)address - local.targets.base);
g_ctx->log(TText16() << (Utf8ToUtf16)line);
}
NativePointer* ptr = NativePointer::newInstance();
Expand Down Expand Up @@ -477,10 +476,6 @@ void CachedPdb::search(JsValue masks, JsValue cb) throws(kr::JsException)

m_pdb.search(nullptr, [&](Text name, void* address, uint32_t typeId) {
auto iter = finder.find(name);
if (name.endsWith("_fptr"))
{
debug();
}
if (finder.end() == iter) return true;

NativePointer* ptr = NativePointer::newInstance();
Expand Down
56 changes: 13 additions & 43 deletions bdsx/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ namespace
size_t skipCount;
};

using __scrt_common_main_seh_t = int(*)();
using main_t = int(*)(int, char**, char**);
main_t s_bedrockMain;
__scrt_common_main_seh_t s_bedrockSehMain;
constexpr size_t ORIGINAL_BYTES_COUNT = 12;
byte s_bedrockMainOriginal12Bytes[ORIGINAL_BYTES_COUNT];

TText16 readNativeStackFromExceptionPointer(EXCEPTION_POINTERS* ptr) noexcept
{
Expand All @@ -70,7 +70,7 @@ int nodeStart(int argc, char** argv) noexcept
{
return nodegate::start(argc, argv);
}
__except (GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_CONTINUE_SEARCH : runtimeError::raise(GetExceptionInformation()))
__except (GetExceptionCode() == EXCEPTION_BREAKPOINT ? EXCEPTION_CONTINUE_SEARCH : (runtimeError::raise(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER))
{
return -1;
}
Expand Down Expand Up @@ -133,54 +133,24 @@ BOOL WINAPI DllMain(
}

// load pdb
if (!g_pdb.getProcAddresses(CachedPdb::predefinedForCore.data(), View<Text>{ "__scrt_common_main_seh"_tx }, [](Text name, void* fnptr, void*) {
s_bedrockSehMain = (__scrt_common_main_seh_t)fnptr;
PdbReader::setOptions(0);
if (!g_pdb.getProcAddresses(CachedPdb::predefinedForCore.data(), View<Text>{ "main"_tx }, [](Text name, void* fnptr, void*) {
s_bedrockMain = (main_t)fnptr;
}, nullptr, false))
{
terminate(-1);
}
if (s_bedrockSehMain == nullptr)
if (s_bedrockMain == nullptr)
{
cerr << "[BDSX] Failed to find entry of bedrock_server.exe" << endl;
cerr << "[BDSX] Failed to find 'main' of bedrock_server.exe" << endl;
terminate(-1);
}
PdbReader::setOptions(0);

// hook main

size_t offset_hook = 0xff;
size_t offset_call = offset_hook + 0x8;

int32_t offset_main_call = *(Unaligned<int32_t>*)((byte*)s_bedrockSehMain + offset_call + 1);
s_bedrockMain = (main_t)((byte*)s_bedrockSehMain + offset_call + 5 + offset_main_call);

/*
mov r8,rax
mov rdx,rdi
mov ecx,dword ptr ds:[rbx]
call <bedrock_server.main>
*/
static const byte ORIGINAL_CODE[] = {
0x4C, 0x8B, 0xC0,
0x48, 0x8B, 0xD7,
0x8B, 0x0B,
0xE8, 0xB0, 0x47, 0xFF, 0xFE
};

JitFunction junction(64);
junction.mov(R8, RAX);
junction.mov(RDX, RDI);
junction.mov(RCX, QwordPtr, RBX);
junction.jump64(nodeStart, RAX);
CodeDiff diff = junction.patchTo((byte*)s_bedrockSehMain + offset_hook, ORIGINAL_CODE, R9, false, { {9, 13} });
if (!diff.succeeded())
{
cerr << "[BDSX] entry point hooking failed, bytes did not matched at {";
for (const pair<size_t, size_t>& v : diff)
{
cerr << " {" << v.first << ", " << v.second << "}, ";
}
cerr << '}' << endl;
memcpy(s_bedrockMainOriginal12Bytes, s_bedrockMain, ORIGINAL_BYTES_COUNT);
Unprotector unpro(s_bedrockMain, ORIGINAL_BYTES_COUNT);
CodeWriter writer((void*)unpro, ORIGINAL_BYTES_COUNT);
writer.jump(nodeStart, RAX);
}
}
return true;
Expand Down Expand Up @@ -319,7 +289,6 @@ namespace
}
}


void nodegate::initNativeModule(void* exports_raw) noexcept
{
g_ctx.create();
Expand All @@ -343,6 +312,7 @@ void nodegate::initNativeModule(void* exports_raw) noexcept
bedrock_server_exe.set(u"args", VoidPointer::make(s_args));
bedrock_server_exe.set(u"argsLine", (Text16)unwide(GetCommandLineW()));
bedrock_server_exe.set(u"main", VoidPointer::make(s_bedrockMain));
bedrock_server_exe.set(u"mainOriginal12Bytes", VoidPointer::make(s_bedrockMainOriginal12Bytes));
bedrock_server_exe.setMethod(u"forceKill", kr::terminate);
}

Expand Down
15 changes: 15 additions & 0 deletions bdsx/mtqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ void MultiThreadQueue::dequeue(void* dest) noexcept
return;
}
}
bool MultiThreadQueue::tryDequeue(void* dest) noexcept
{
auto pair = m_queue.dequeue();
if (pair.first == nullptr) return false;
memcpy(dest, pair.first + 1, m_itemSize);
pair.first->release();
return true;
}
void MultiThreadQueue::enqueueJs(VoidPointer* src) noexcept
{
enqueue(src->getAddressRaw());
Expand All @@ -47,14 +55,21 @@ void MultiThreadQueue::dequeueJs(VoidPointer* dest) noexcept
{
dequeue(dest->getAddressRaw());
}
bool MultiThreadQueue::tryDequeueJs(VoidPointer* dest) noexcept
{
return tryDequeue(dest->getAddressRaw());
}

void MultiThreadQueue::initMethods(JsClassT<MultiThreadQueue>* cls) noexcept
{
cls->setMethod(u"enqueue", &MultiThreadQueue::enqueueJs);
cls->setMethod(u"dequeue", &MultiThreadQueue::dequeueJs);
cls->setMethod(u"tryDequeue", &MultiThreadQueue::tryDequeueJs);

void(* enqueue)(MultiThreadQueue * queue, void* src) = [](MultiThreadQueue* queue, void* src) { queue->enqueue(src); };
cls->set(u"enqueue", VoidPointer::make(enqueue));
void(* dequeue)(MultiThreadQueue * queue, void* dest) = [](MultiThreadQueue* queue, void* dest) { queue->dequeue(dest); };
cls->set(u"dequeue", VoidPointer::make(dequeue));
bool(* tryDequeue)(MultiThreadQueue * queue, void* dest) = [](MultiThreadQueue* queue, void* dest) { return queue->tryDequeue(dest); };
cls->set(u"tryDequeue", VoidPointer::make(tryDequeue));
}
2 changes: 2 additions & 0 deletions bdsx/mtqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ class MultiThreadQueue :public kr::JsObjectT<MultiThreadQueue, VoidPointer>
MultiThreadQueue(const kr::JsArguments& args) throws(kr::JsException);
void enqueue(void* src) noexcept;
void dequeue(void* dest) noexcept;
bool tryDequeue(void* dest) noexcept;
void enqueueJs(VoidPointer* src) noexcept;
void dequeueJs(VoidPointer* dest) noexcept;
bool tryDequeueJs(VoidPointer* dest) noexcept;

static void initMethods(kr::JsClassT<MultiThreadQueue>* cls) noexcept;

Expand Down
27 changes: 11 additions & 16 deletions bdsx/sehandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "voidpointer.h"
#include "nodegate.h"
#include "jsctx.h"
#include "unwind.h"

#include <KR3/win/windows.h>
#include <KR3/mt/criticalsection.h>
Expand Down Expand Up @@ -74,6 +75,12 @@ namespace
}
return u"[Unknown]";
}
bool addFunctionTable(VoidPointer* baseptr, int unwindcount, int fncount) throws(JsException)
{
if (baseptr == nullptr) throw JsException(u"Invalid arguments");
DWORD64 base = (DWORD64)baseptr->getAddressRawSafe();
return RtlAddFunctionTable((RUNTIME_FUNCTION*)(base + unwindcount * sizeof(UNWIND_INFO)), fncount, base);
}
}

kr::Text16 runtimeError::codeToString(unsigned int errorCode) noexcept
Expand Down Expand Up @@ -109,7 +116,7 @@ kr::Text16 runtimeError::codeToString(unsigned int errorCode) noexcept
}
}

int runtimeError::raise(EXCEPTION_POINTERS* exptr) noexcept
ATTR_NORETURN void runtimeError::raise(EXCEPTION_POINTERS* exptr) noexcept
{
static DWORD raising = 0;
if (raising != 0) Sleep(INFINITE);
Expand Down Expand Up @@ -148,7 +155,6 @@ int runtimeError::raise(EXCEPTION_POINTERS* exptr) noexcept
debug();
}
#endif


for (;;)
{
Expand Down Expand Up @@ -183,7 +189,6 @@ int runtimeError::raise(EXCEPTION_POINTERS* exptr) noexcept
}
}
Sleep(INFINITE);
return EXCEPTION_EXECUTE_HANDLER;
}
void runtimeError::setHandler(kr::JsValue handler) noexcept
{
Expand All @@ -206,16 +211,6 @@ void runtimeError::fire(JsValueRef error) noexcept
}
terminate(-1);
}
SehHandler* runtimeError::beginHandler() noexcept
{
return (SehHandler*)_set_se_translator([](unsigned int code, EXCEPTION_POINTERS* exptr) {
raise(exptr);
});
}
void runtimeError::endHandler(SehHandler* old) noexcept
{
_set_se_translator((_se_translator_function)old);
}
kr::JsValue runtimeError::getError() noexcept
{
CsLock lock = s_stackLock;
Expand All @@ -226,8 +221,8 @@ kr::JsValue runtimeError::getError() noexcept
TSZ16 message;
message << u"RuntimeError: " << codeToString(code) << u"(0x" << hexf(code, 8) << u')';
JsValue err = runtimeErrorAllocator.call((Text16)message);
err.set(u"code", (int)code);


err.set(s_field->nativeStack, s_nativeExceptionStack);
if (s_threadId != s_field->threadId)
{
Expand All @@ -242,14 +237,14 @@ kr::JsValue runtimeError::getRuntimeErrorClass() noexcept
{
return (JsValue)s_field->runtimeErrorClass;
}

kr::JsValue runtimeError::getNamespace() noexcept
{
JsValue runtimeError = JsNewObject;
runtimeError.set(u"beginHandler", VoidPointer::make(beginHandler));
runtimeError.set(u"endHandler", VoidPointer::make(endHandler));
runtimeError.setMethod(u"codeToString", codeToString);
runtimeError.set(u"raise", VoidPointer::make(raise));
runtimeError.setMethod(u"setHandler", setHandler);
runtimeError.set(u"fire", VoidPointer::make(fire));
runtimeError.setMethod(u"addFunctionTable", addFunctionTable);
return runtimeError;
}
4 changes: 1 addition & 3 deletions bdsx/sehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS;

namespace runtimeError
{
int raise(EXCEPTION_POINTERS* exptr) noexcept;
ATTR_NORETURN void raise(EXCEPTION_POINTERS* exptr) noexcept;
void setHandler(kr::JsValue listener) noexcept;
ATTR_NORETURN void fire(JsValueRef error) noexcept;

kr::Text16 codeToString(unsigned int errorCode) noexcept;
SehHandler* beginHandler() noexcept;
void endHandler(SehHandler* old) noexcept;
kr::JsValue getError() noexcept;
kr::JsValue getRuntimeErrorClass() noexcept;
kr::JsValue getNamespace() noexcept;
Expand Down
9 changes: 0 additions & 9 deletions bdsx/staticpointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,6 @@ StaticPointer::StaticPointer(const JsArguments& args) noexcept
else m_address = nullptr;
}

TText16 StaticPointer::toString() noexcept
{
TText16 out;
out << hexf((uintptr_t)m_address, sizeof(uintptr_t) * 2);
return out;
}

bool StaticPointer::getBoolean(int offset) throws(JsException)
{
return _getas<bool>(offset);
Expand Down Expand Up @@ -587,8 +580,6 @@ void StaticPointer::setJsValueRef(JsValue v, int offset) throws(kr::JsException)

void StaticPointer::initMethods(JsClassT<StaticPointer>* cls) noexcept
{
cls->setMethod(u"toString", &StaticPointer::toString);

cls->setMethod(u"getBoolean", &StaticPointer::getBoolean);
cls->setMethod(u"getUint8", &StaticPointer::getUint8);
cls->setMethod(u"getUint16", &StaticPointer::getUint16);
Expand Down
2 changes: 0 additions & 2 deletions bdsx/staticpointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ class StaticPointer :public kr::JsObjectT<StaticPointer, VoidPointer>
kr::JsValue getJsValueRef(int offset) throws(kr::JsException);
void setJsValueRef(kr::JsValue v, int offset) throws(kr::JsException);

kr::TText16 toString() noexcept;

static void initMethods(kr::JsClassT<StaticPointer>* cls) noexcept;

private:
Expand Down
57 changes: 57 additions & 0 deletions bdsx/unwind.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#pragma once

typedef unsigned char UBYTE;
typedef unsigned short USHORT;
typedef unsigned long ULONG;

typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0, /* info == register number */
UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
UWOP_SAVE_XMM128 = 8, /* info == XMM reg number, offset in next slot */
UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
} UNWIND_CODE_OPS;

typedef union _UNWIND_CODE {
struct {
UBYTE CodeOffset;
UBYTE UnwindOp : 4;
UBYTE OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, * PUNWIND_CODE;

typedef struct _UNWIND_INFO {
UBYTE Version : 3;
UBYTE Flags : 5;
UBYTE SizeOfProlog;
UBYTE CountOfCodes;
UBYTE FrameRegister : 4;
UBYTE FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
/* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
* union {
* OPTIONAL ULONG ExceptionHandler;
* OPTIONAL ULONG FunctionEntry;
* };
* OPTIONAL ULONG ExceptionData[]; */
} UNWIND_INFO, * PUNWIND_INFO;

#define GetUnwindCodeEntry(info, index) \
((info)->UnwindCode[index])

#define GetLanguageSpecificDataPtr(info) \
((PVOID)&GetUnwindCodeEntry((info),((info)->CountOfCodes + 1) & ~1))

#define GetExceptionHandler(base, info) \
((PEXCEPTION_HANDLER)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))

#define GetChainedFunctionEntry(base, info) \
((PRUNTIME_FUNCTION)((base) + *(PULONG)GetLanguageSpecificDataPtr(info)))

#define GetExceptionDataPtr(info) \
((PVOID)((PULONG)GetLanguageSpecificData(info) + 1)
2 changes: 1 addition & 1 deletion bdsx/version.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

set BDSX_CORE_VERSION=1.0.2.0
set BDSX_CORE_VERSION=1.0.3.0

0 comments on commit b83ffaa

Please sign in to comment.