添加捕获C++异常的方法
LazuliKao opened this issue · 9 comments
在.net framework 可以通过HandleProcessCorruptedStateExceptions标注,使得代码中的AccessViolationException和SEHException得以捕获,从而避免崩服
可惜.net6上,这项外星科技被移除了,急需一个能安全执行的方法
需要一个叫做TryCatch的方法,传入一个.net的托管Action对象(委托),或者传入函数指针,在C++中安全的执行,并翻译AccessViolationException和SEHException给.net托管代码
可惜.net6上,这项外星科技被移除了
毕竟是Windows平台限定私货(
有时间再做翻译和映射,写不动了(
测试代码
LLNET.Hook.NativeAPI.TryCatch(() =>
{
MC.Player p = new(IntPtr.Zero);
p.TalkAs("test");
}, out _);
还是没能捕获System.AccessViolationException
测试PInvoke在C++库抛出
TESTPlugin.zip
不过纯托管指针操作套上LLNET.Hook.NativeAPI.TryCatch已经安全了
感觉如果是经过PInvoke的都捉不到异常,估计是被clr直接拦下来了
想要实现这种东西估计得用点黑魔法(
已找到解决方法
首先Hookcoreclr.dll
的LogInfoForFatalError方法
PublicSymbol ?LogInfoForFatalError@@YAXIPEB_W00@Z
RelativeVirtualAddress 2480668
(这个方法在遭受致命错误后会被clr调用,随即会终止运行时)
在该方法内直接throw 一个C++的异常,就可以在外边抓到异常,而不是走clr的逻辑终止程序
对于如何得到该方法的基址
有以下方法:
1.微软符号服务器获取pdb,解析pdb获取地址(麻烦,首次运行还得下载50MB的pdb
2.提前根据不同编译的coreclr获取地址,通过已有数据做个通用的内存特征码,通过特征码进行内存寻址
打算通过内存寻址实现,部分参考Horion,在fix/CLRFatalError分支
对于如何得到该方法的基址 有以下方法: 1.微软符号服务器获取pdb,解析pdb获取地址(麻烦,首次运行还得下载50MB的pdb 2.提前根据不同编译的coreclr获取地址,通过已有数据做个通用的内存特征码,通过特征码进行内存寻址
打算通过内存寻址实现,部分参考Horion,在FixCLRFatalError分支或者直接fork一个coreclr?( https://github.com/dotnet/runtime/tree/v6.0.8/src/coreclr
相关函数在这 https://github.com/dotnet/runtime/blob/v6.0.8/src/coreclr/vm/eepolicy.cpp#L345
void LogInfoForFatalError(UINT exitCode, LPCWSTR pszMessage, LPCWSTR errorSource, LPCWSTR argExceptionString) { WRAPPER_NO_CONTRACT; static Thread *const FatalErrorNotSeenYet = nullptr; static Thread *const FatalErrorLoggingFinished = reinterpret_cast<Thread *>(1); static Thread *volatile s_pCrashingThread = FatalErrorNotSeenYet; Thread *pThread = GetThreadNULLOk(); Thread *pPreviousThread = InterlockedCompareExchangeT<Thread *>(&s_pCrashingThread, pThread, FatalErrorNotSeenYet); if (pPreviousThread == pThread) { PrintToStdErrA("Fatal error while logging another fatal error.\n"); return; } else if (pPreviousThread != nullptr) { while (s_pCrashingThread != FatalErrorLoggingFinished) { ClrSleepEx(50, /*bAlertable*/ FALSE); } return; } EX_TRY { if (exitCode == (UINT)COR_E_FAILFAST) { PrintToStdErrA("Process terminated. "); } else { PrintToStdErrA("Fatal error. "); } if (errorSource != NULL) { PrintToStdErrW(errorSource); PrintToStdErrA("\n"); } if (pszMessage != NULL) { PrintToStdErrW(pszMessage); } else { // If no message was passed in, generate it from the exitCode SString exitCodeMessage; GetHRMsg(exitCode, exitCodeMessage); PrintToStdErrW((LPCWSTR)exitCodeMessage); } PrintToStdErrA("\n"); if (pThread && errorSource == NULL) { LogCallstackForLogWorker(GetThread()); if (argExceptionString != NULL) { PrintToStdErrW(argExceptionString); } } } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions) InterlockedCompareExchangeT<Thread *>(&s_pCrashingThread, FatalErrorLoggingFinished, pThread); }
是的就是这个,