#include "stdinc.h" #include "debmacro.h" #include "util.h" #include "fusionntdll.h" #if !FUSION_URT int FusionpCompareStrings( PCWSTR psz1, SIZE_T cch1, PCWSTR psz2, SIZE_T cch2, bool fCaseInsensitive ) { UNICODE_STRING s1, s2; s1.Buffer = const_cast(psz1); s1.Length = static_cast(cch1 * sizeof(WCHAR)); s1.MaximumLength = s1.Length; s2.Buffer = const_cast(psz2); s2.Length = static_cast(cch2 * sizeof(WCHAR)); s2.MaximumLength = s2.Length; return ::FusionpRtlCompareUnicodeString(&s1, &s2, fCaseInsensitive); } int FusionpCompareStrings( const CBaseStringBuffer &rbuff1, PCWSTR psz2, SIZE_T cch2, bool fCaseInsensitive ) { return ::FusionpCompareStrings(rbuff1, rbuff1.Cch(), psz2, cch2, fCaseInsensitive); } int FusionpCompareStrings( PCWSTR psz1, SIZE_T cch1, const CBaseStringBuffer &rbuff2, bool fCaseInsensitive ) { return ::FusionpCompareStrings(psz1, cch1, rbuff2, rbuff2.Cch(), fCaseInsensitive); } int FusionpCompareStrings( const CBaseStringBuffer &rbuff1, const CBaseStringBuffer &rbuff2, bool fCaseInsensitive ) { return ::FusionpCompareStrings(rbuff1, rbuff1.Cch(), rbuff2, rbuff2.Cch(), fCaseInsensitive); } #endif #if !FUSION_STATIC_NTDLL #define INIT_WITH_DOWNLEVEL(rettype, calltype, api, argsin, argsout) \ rettype calltype Fusionp ## api ## _Init argsin; \ rettype calltype Fusionp ## api ## _DownlevelFallback argsin; \ rettype (calltype * g_Fusionp ## api) argsin = &::Fusionp ## api ## _Init; \ rettype \ calltype \ Fusionp ## api ## _Init argsin \ { \ InterlockedExchangePointer((PVOID *) &g_Fusionp ## api, ::GetProcAddress(::GetModuleHandleW(L"NTDLL.DLL"), #api)); \ if (g_Fusionp ## api == NULL) \ InterlockedExchangePointer((PVOID *) &g_Fusionp ## api, &::Fusionp ## api ## _DownlevelFallback); \ return (*g_Fusionp ## api) argsout; \ } __declspec(noreturn) void FusionpFailNtdllDynlink(const char* s) { DWORD dwLastError = ::GetLastError(); char buf[64]; buf[sizeof(buf) - 1] = 0; _snprintf(buf, RTL_NUMBER_OF(buf) - 1, "SXS2000: Ntdll dynlink %s failed\n", s); OutputDebugStringA(buf); TerminateProcess(GetCurrentProcess(), dwLastError); } #define INIT_NO_DOWNLEVEL(rettype, calltype, api, argsin, argsout) \ rettype calltype Fusionp ## api ## _Init argsin; \ rettype (calltype * g_Fusionp ## api) argsin = &::Fusionp ## api ## _Init; \ rettype \ calltype \ Fusionp ## api ## _Init argsin \ { \ InterlockedExchangePointer((PVOID *) &g_Fusionp ## api, ::GetProcAddress(::GetModuleHandleW(L"NTDLL.DLL"), #api)); \ if (g_Fusionp ## api == NULL) \ ::FusionpFailNtdllDynlink(#api); \ return (*g_Fusionp ## api) argsout; \ } INIT_NO_DOWNLEVEL(WCHAR, NTAPI, RtlUpcaseUnicodeChar, (WCHAR wch), (wch)) INIT_NO_DOWNLEVEL(WCHAR, NTAPI, RtlDowncaseUnicodeChar, (WCHAR wch), (wch)) INIT_WITH_DOWNLEVEL(NTSTATUS, NTAPI, NtQueryDebugFilterState, (ULONG ComponentId, ULONG Level), (ComponentId, Level)) INIT_NO_DOWNLEVEL(LONG, NTAPI, RtlCompareUnicodeString, (PCUNICODE_STRING String1, PCUNICODE_STRING String2, BOOLEAN CaseInSensitive), (String1, String2, CaseInSensitive)) INIT_NO_DOWNLEVEL(LONG, NTAPI, RtlUnhandledExceptionFilter, (struct _EXCEPTION_POINTERS *ExceptionInfo), (ExceptionInfo)) INIT_NO_DOWNLEVEL(NTSTATUS, NTAPI, NtAllocateLocallyUniqueId, (PLUID Luid), (Luid)) INIT_WITH_DOWNLEVEL(ULONG, NTAPI, vDbgPrintExWithPrefix, (PCSTR Prefix, IN ULONG ComponentId, IN ULONG Level, IN PCSTR Format, va_list arglist), (Prefix, ComponentId, Level, Format, arglist)) INIT_NO_DOWNLEVEL(DWORD, NTAPI, RtlNtStatusToDosError, (NTSTATUS st), (st)) INIT_WITH_DOWNLEVEL(NTSTATUS, NTAPI, RtlHashUnicodeString, (const UNICODE_STRING *String, BOOLEAN CaseInSensitive, ULONG HashAlgorithm, PULONG HashValue), (String, CaseInSensitive, HashAlgorithm, HashValue)) INIT_NO_DOWNLEVEL(NTSTATUS, NTAPI, RtlExpandEnvironmentStrings_U, (PVOID Environment, PUNICODE_STRING Source, PUNICODE_STRING Destination, PULONG ReturnedLength), (Environment, Source, Destination, ReturnedLength)) INIT_NO_DOWNLEVEL(VOID, NTAPI, RtlAssert, (PVOID FailedAssertion, PVOID FileName, ULONG LineNumber, PCSTR Message), (FailedAssertion, FileName, LineNumber, Message)) void FusionpInitializeNTDLLPtr( PVOID *ppv, PCSTR szFunctionName ) { HMODULE hMod = ::GetModuleHandleW(L"NTDLL.DLL"); PVOID pvTemp = ::GetProcAddress(hMod, szFunctionName); InterlockedExchangePointer(ppv, pvTemp); } ULONG NTAPI FusionpvDbgPrintExWithPrefix_DownlevelFallback(PCSTR Prefix, IN ULONG ComponentId, IN ULONG Level, IN PCSTR Format, va_list arglist) { CHAR Buffer[512]; // same as code in rtl 4/23/2001 __try { SSIZE_T cb = ::strlen(Prefix); Buffer[sizeof(Buffer) - 1] = 0; strcpy(Buffer, Prefix); ::_vsnprintf(Buffer + cb , sizeof(Buffer) - cb - 1, Format, arglist); } __except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } ::OutputDebugStringA(Buffer); return STATUS_SUCCESS; } NTSTATUS NTAPI FusionpRtlHashUnicodeString_DownlevelFallback( const UNICODE_STRING *String, BOOLEAN CaseInSensitive, ULONG HashAlgorithm, PULONG HashValue ) { NTSTATUS Status = STATUS_SUCCESS; ULONG TmpHashValue = 0; ULONG Chars; PCWSTR Buffer; if ((String == NULL) || (HashValue == NULL)) { Status = STATUS_INVALID_PARAMETER; goto Exit; } Buffer = String->Buffer; *HashValue = 0; Chars = String->Length / sizeof(WCHAR); switch (HashAlgorithm) { default: Status = STATUS_INVALID_PARAMETER; goto Exit; break; case HASH_STRING_ALGORITHM_DEFAULT: case HASH_STRING_ALGORITHM_X65599: if (CaseInSensitive) { while (Chars-- != 0) { WCHAR Char = *Buffer++; TmpHashValue = (TmpHashValue * 65599) + ::FusionpRtlUpcaseUnicodeChar(Char); } } else { while (Chars-- != 0) TmpHashValue = (TmpHashValue * 65599) + *Buffer++; } break; } *HashValue = TmpHashValue; Status = STATUS_SUCCESS; Exit: return Status; } NTSTATUS NTAPI FusionpNtQueryDebugFilterState_DownlevelFallback(ULONG ComponentId, ULONG Level) { return FALSE; // total abuse of NTSTATUS API but it's how NtQueryDebugFilterState is written... } #endif