结构化异常代码通过NTSTATUS编号定义。虽然有人从MS建议here(这篇文章已被转移到here)使用FormatMessage()将NTSTATUS数字转换为字符串,我不会这样做。标志FORMAT_MESSAGE_FROM_SYSTEM用于将GetLastError()的结果转换为字符串,因此在这里没有意义。将标志FORMAT_MESSAGE_FROM_HMODULE与ntdll.dll沿着使用会导致某些代码的结果不正确。例如,对于EXCEPTION_ACCESS_VIOLATION,您将得到The instruction at 0x,这不是很有用:)。 当您查看存储在ntdll.dll中的字符串时,很明显,其中许多字符串应该与printf()函数一起使用,而不是与FormatMessage()一起使用。例如,EXCEPTION_ACCESS_VIOLATION的字符串是: The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.个 FormatMessage()将%0视为转义序列,表示消息终止符,而不是插入。插入为%1到%99。这就是为什么标志FORMAT_MESSAGE_IGNORE_INSERTS没有任何区别。 您可能希望从ntdll.dll加载字符串并将其传递给vprintf(),但您需要完全按照字符串指定的方式准备参数(例如:对于EXCEPTION_ACCESS_VIOLATION,它是unsigned long,unsigned long,char*)。这种方法有一个主要缺点:ntdll.dll中参数的数量、顺序或大小的任何更改都可能破坏代码。 因此,将字符串硬编码到您自己的代码中更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是危险的:),而且用于其他函数。这只是故障的另一种可能性。
// Returns length of resulting string, excluding null-terminator.
// Use LocalFree() to free the buffer when it is no longer needed.
// Returns 0 upon failure, use GetLastError() to get error details.
DWORD FormatNtStatus(NTSTATUS nsCode, TCHAR **ppszMessage) {
// Get handle to ntdll.dll.
HMODULE hNtDll = LoadLibrary(_T("NTDLL.DLL"));
// Check for fail, user may use GetLastError() for details.
if (hNtDll == NULL) return 0;
// Call FormatMessage(), note use of RtlNtStatusToDosError().
DWORD dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
hNtDll, RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)ppszMessage, 0, NULL);
// Free loaded dll module and decrease its reference count.
FreeLibrary(hNtDll);
return dwRes;
}
4条答案
按热度按时间llew8vvj1#
结构化异常代码通过NTSTATUS编号定义。虽然有人从MS建议here(这篇文章已被转移到here)使用FormatMessage()将NTSTATUS数字转换为字符串,我不会这样做。标志
FORMAT_MESSAGE_FROM_SYSTEM
用于将GetLastError()的结果转换为字符串,因此在这里没有意义。将标志FORMAT_MESSAGE_FROM_HMODULE
与ntdll.dll
沿着使用会导致某些代码的结果不正确。例如,对于EXCEPTION_ACCESS_VIOLATION
,您将得到The instruction at 0x
,这不是很有用:)。当您查看存储在
ntdll.dll
中的字符串时,很明显,其中许多字符串应该与printf()函数一起使用,而不是与FormatMessage()一起使用。例如,EXCEPTION_ACCESS_VIOLATION
的字符串是:The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.
个FormatMessage()将
%0
视为转义序列,表示消息终止符,而不是插入。插入为%1到%99。这就是为什么标志FORMAT_MESSAGE_IGNORE_INSERTS
没有任何区别。您可能希望从
ntdll.dll
加载字符串并将其传递给vprintf(),但您需要完全按照字符串指定的方式准备参数(例如:对于EXCEPTION_ACCESS_VIOLATION
,它是unsigned long
,unsigned long
,char*
)。这种方法有一个主要缺点:ntdll.dll
中参数的数量、顺序或大小的任何更改都可能破坏代码。因此,将字符串硬编码到您自己的代码中更安全、更容易。我发现在没有与我协调的情况下使用其他人准备的字符串是危险的:),而且用于其他函数。这只是故障的另一种可能性。
ijnw1ujt2#
是的。它是一个
NTSTATUS
,所以使用FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULE
,并从LoadLibrary("NTDLL.DLL")
传递HMODULE
Source: KB259693 (archived)
mrfwxfqh3#
正确管理某些NTSTATUS字符串的流格式是很复杂的。您应该考虑将其转换为带有RtlNtStatusToDosError()的Win32消息,该消息的头为Winternl.h。在链接器输入中需要有ntdll.lib。
示例实施方式:
字符集
6jjcrrmo4#
我建议你use bugslayer。只需使用
EXCEPTION_POINTERS
调用GetFaultReason
。此外,您可以使用
GetFirstStackTraceString
和GetNextStackTraceString
遍历堆栈。