From b4b3e32b098a5927f6d795bd9a49e9b229cceeaa Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sun, 30 Mar 2025 12:54:22 +0200 Subject: [PATCH] Port AVX512 support from TitanEngine https://github.com/x64dbg/TitanEngine/pull/22 --- GleeBug/GleeBug.vcxproj | 9 +- GleeBug/ntdll.h | 4 +- MyDebugger/MyDebugger.vcxproj | 9 +- StaticEngine/StaticEngine.vcxproj | 9 +- StaticEngine/TitanEngine.h | 18 ++ StaticEngine/TitanEngineEmulator.cpp | 10 + TitanEngineEmulator/Emulator.h | 34 ++- TitanEngineEmulator/TitanEngine.h | 18 ++ TitanEngineEmulator/TitanEngineEmulator.cpp | 197 ++++++++++++++++++ .../TitanEngineEmulator.vcxproj | 9 +- TitanEngineEmulator/ntdll.h | 8 +- 11 files changed, 293 insertions(+), 32 deletions(-) diff --git a/GleeBug/GleeBug.vcxproj b/GleeBug/GleeBug.vcxproj index 2d8bb4c..42d5908 100644 --- a/GleeBug/GleeBug.vcxproj +++ b/GleeBug/GleeBug.vcxproj @@ -21,31 +21,32 @@ {B65A3680-9B6B-44E6-A046-649F94DF9F56} GleeBug + 10.0 StaticLibrary true - v140_xp + v141_xp MultiByte StaticLibrary true - v140_xp + v141_xp MultiByte StaticLibrary false - v140_xp + v141_xp true MultiByte StaticLibrary false - v140_xp + v141_xp true MultiByte diff --git a/GleeBug/ntdll.h b/GleeBug/ntdll.h index 5064065..917d1fb 100644 --- a/GleeBug/ntdll.h +++ b/GleeBug/ntdll.h @@ -2511,7 +2511,7 @@ typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE]; -#define FLS_MAXIMUM_AVAILABLE 128 +#define NTDLL_FLS_MAXIMUM_AVAILABLE 128 #define TLS_MINIMUM_AVAILABLE 64 #define TLS_EXPANSION_SLOTS 1024 @@ -2656,7 +2656,7 @@ typedef struct _PEB PVOID* FlsCallback; LIST_ENTRY FlsListHead; PVOID FlsBitmap; - ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + ULONG FlsBitmapBits[NTDLL_FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; ULONG FlsHighIndex; PVOID WerRegistrationData; diff --git a/MyDebugger/MyDebugger.vcxproj b/MyDebugger/MyDebugger.vcxproj index ffaba9f..9288147 100644 --- a/MyDebugger/MyDebugger.vcxproj +++ b/MyDebugger/MyDebugger.vcxproj @@ -21,31 +21,32 @@ {4083DE5A-582F-4B15-B6F0-CB866E66F8C4} MyDebugger + 10.0 Application true - v140_xp + v141_xp MultiByte Application true - v140_xp + v141_xp MultiByte Application false - v140_xp + v141_xp true MultiByte Application false - v140_xp + v141_xp true MultiByte diff --git a/StaticEngine/StaticEngine.vcxproj b/StaticEngine/StaticEngine.vcxproj index d537b2f..2d044ba 100644 --- a/StaticEngine/StaticEngine.vcxproj +++ b/StaticEngine/StaticEngine.vcxproj @@ -21,31 +21,32 @@ {8E0C7F46-89CC-4510-BC17-07513A31BC7E} StaticEngine + 10.0 DynamicLibrary true - v140_xp + v141_xp MultiByte DynamicLibrary true - v140_xp + v141_xp MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte diff --git a/StaticEngine/TitanEngine.h b/StaticEngine/TitanEngine.h index 0a44c83..c03091a 100644 --- a/StaticEngine/TitanEngine.h +++ b/StaticEngine/TitanEngine.h @@ -599,6 +599,12 @@ typedef struct XmmRegister_t High; //AVX part } YmmRegister_t; +typedef struct +{ + YmmRegister_t Low; //AVX part + YmmRegister_t High; //AVX-512 part +} ZmmRegister_t; + typedef struct { BYTE data[10]; @@ -664,6 +670,16 @@ typedef struct #endif } TITAN_ENGINE_CONTEXT_t; +typedef struct +{ +#ifdef _WIN64 + ZmmRegister_t ZmmRegisters[32]; +#else // x86 + ZmmRegister_t ZmmRegisters[8]; +#endif + ULONGLONG Opmask[8]; +} TITAN_ENGINE_CONTEXT_AVX512_t; + #ifdef __cplusplus extern "C" { @@ -853,6 +869,8 @@ __declspec(dllexport) bool TITCALL SetContextDataEx(HANDLE hActiveThread, DWORD __declspec(dllexport) bool TITCALL SetContextData(DWORD IndexOfRegister, ULONG_PTR NewRegisterValue); __declspec(dllexport) bool TITCALL GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext); __declspec(dllexport) bool TITCALL SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext); +__declspec(dllexport) bool TITCALL GetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext); +__declspec(dllexport) bool TITCALL SetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext); __declspec(dllexport) void TITCALL ClearExceptionNumber(); __declspec(dllexport) long TITCALL CurrentExceptionNumber(); __declspec(dllexport) bool TITCALL MatchPatternEx(HANDLE hProcess, void* MemoryToCheck, int SizeOfMemoryToCheck, void* PatternToMatch, int SizeOfPatternToMatch, PBYTE WildCard); diff --git a/StaticEngine/TitanEngineEmulator.cpp b/StaticEngine/TitanEngineEmulator.cpp index e050e09..37d4074 100644 --- a/StaticEngine/TitanEngineEmulator.cpp +++ b/StaticEngine/TitanEngineEmulator.cpp @@ -171,6 +171,16 @@ __declspec(dllexport) void TITCALL Getx87FPURegisters(x87FPURegister_t x87FPUReg emu.Getx87FPURegisters(x87FPURegisters, titcontext); } +__declspec(dllexport) bool TITCALL GetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) +{ + return false; +} + +__declspec(dllexport) bool TITCALL SetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) +{ + return false; +} + //PE __declspec(dllexport) bool TITCALL StaticFileLoad(const char* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) { diff --git a/TitanEngineEmulator/Emulator.h b/TitanEngineEmulator/Emulator.h index 35dae23..fddbcca 100644 --- a/TitanEngineEmulator/Emulator.h +++ b/TitanEngineEmulator/Emulator.h @@ -1170,18 +1170,32 @@ private: //functions return dwLastError; } + static DWORD GetNtBuildNumberWindows7() + { + auto p_RtlGetVersion = (NTSTATUS(WINAPI*)(PRTL_OSVERSIONINFOW))GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetVersion"); + RTL_OSVERSIONINFOW info = { sizeof(info) }; + if (p_RtlGetVersion && p_RtlGetVersion(&info) == 0) + return info.dwBuildNumber; + else + return 0; + } + + static DWORD GetNtBuildNumber() + { + // https://www.vergiliusproject.com/kernels/x64/Windows%2010%20%7C%202016/1507%20Threshold%201/_KUSER_SHARED_DATA + auto NtBuildNumber = *(DWORD*)(0x7FFE0000 + 0x260); + if (NtBuildNumber == 0) + { + // Older versions of Windows + static DWORD NtBuildNumber7 = GetNtBuildNumberWindows7(); + NtBuildNumber = NtBuildNumber7; + } + return NtBuildNumber; + } + static bool isAtleastVista() { - static bool isAtleastVista = false; - static bool isSet = false; - if(isSet) - return isAtleastVista; - OSVERSIONINFO versionInfo = { 0 }; - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&versionInfo); - isAtleastVista = versionInfo.dwMajorVersion >= 6; - isSet = true; - return isAtleastVista; + return GetNtBuildNumber() >= 6000; } //Quote from The Ultimate Anti-Debugging Reference by Peter Ferrie diff --git a/TitanEngineEmulator/TitanEngine.h b/TitanEngineEmulator/TitanEngine.h index c64fb1b..d5dcebb 100644 --- a/TitanEngineEmulator/TitanEngine.h +++ b/TitanEngineEmulator/TitanEngine.h @@ -603,6 +603,12 @@ typedef struct XmmRegister_t High; //AVX part } YmmRegister_t; +typedef struct +{ + YmmRegister_t Low; //AVX part + YmmRegister_t High; //AVX-512 part +} ZmmRegister_t; + typedef struct { BYTE data[10]; @@ -668,6 +674,16 @@ typedef struct #endif } TITAN_ENGINE_CONTEXT_t; +typedef struct +{ +#ifdef _WIN64 + ZmmRegister_t ZmmRegisters[32]; +#else // x86 + ZmmRegister_t ZmmRegisters[8]; +#endif + ULONGLONG Opmask[8]; +} TITAN_ENGINE_CONTEXT_AVX512_t; + #ifdef __cplusplus extern "C" { @@ -859,6 +875,8 @@ __declspec(dllexport) bool TITCALL SetContextDataEx(HANDLE hActiveThread, DWORD __declspec(dllexport) bool TITCALL SetContextData(DWORD IndexOfRegister, ULONG_PTR NewRegisterValue); __declspec(dllexport) bool TITCALL GetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext); __declspec(dllexport) bool TITCALL SetAVXContext(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext); +__declspec(dllexport) bool TITCALL GetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext); +__declspec(dllexport) bool TITCALL SetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext); __declspec(dllexport) void TITCALL ClearExceptionNumber(); __declspec(dllexport) long TITCALL CurrentExceptionNumber(); __declspec(dllexport) bool TITCALL MatchPatternEx(HANDLE hProcess, void* MemoryToCheck, int SizeOfMemoryToCheck, void* PatternToMatch, int SizeOfPatternToMatch, PBYTE WildCard); diff --git a/TitanEngineEmulator/TitanEngineEmulator.cpp b/TitanEngineEmulator/TitanEngineEmulator.cpp index 5b82f3f..5c0fa41 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.cpp +++ b/TitanEngineEmulator/TitanEngineEmulator.cpp @@ -184,6 +184,203 @@ __declspec(dllexport) void TITCALL Getx87FPURegisters(x87FPURegister_t x87FPUReg emu.Getx87FPURegisters(x87FPURegisters, titcontext); } +// AVX-512 constants +#ifndef XSTATE_MASK_AVX512 +#define XSTATE_AVX512_KMASK (5) +#define XSTATE_AVX512_ZMM_H (6) +#define XSTATE_AVX512_ZMM (7) +#define XSTATE_MASK_AVX512 ((1ui64 << (XSTATE_AVX512_KMASK)) | \ + (1ui64 << (XSTATE_AVX512_ZMM_H)) | \ + (1ui64 << (XSTATE_AVX512_ZMM))) +#endif + +static bool SetAVX512ContextFallbackToAVX(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) { + // Fall back to using AVX and ignore the rest + TITAN_ENGINE_CONTEXT_t Avx; + memset(&Avx, 0, sizeof(Avx)); + for (int i = 0; i < _countof(Avx.YmmRegisters); i++) { + Avx.YmmRegisters[i] = titcontext->ZmmRegisters[i].Low; + } + return SetAVXContext(hActiveThread, &Avx); +} + +__declspec(dllexport) bool TITCALL SetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) +{ + if (InitXState() == false) + return false; + + DWORD64 FeatureMask = _GetEnabledXStateFeatures(); + if ((FeatureMask & XSTATE_MASK_AVX512) == 0) + return SetAVX512ContextFallbackToAVX(hActiveThread, titcontext); + + DWORD ContextSize = 0; + BOOL Success = _InitializeContext(NULL, + CONTEXT_ALL | CONTEXT_XSTATE, + NULL, + &ContextSize); + + if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + return false; + + std::vector dataBuffer(ContextSize); + + PCONTEXT Context; + Success = _InitializeContext(dataBuffer.data(), + CONTEXT_ALL | CONTEXT_XSTATE, + &Context, + &ContextSize); + if (Success == FALSE) + return false; + + if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX | XSTATE_MASK_AVX512) == FALSE) + return SetAVX512ContextFallbackToAVX(hActiveThread, titcontext); + + if (GetThreadContext(hActiveThread, Context) == FALSE) + return false; + + if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE) + return false; + + DWORD FeatureLengthSse; + DWORD FeatureLengthAvx; + DWORD FeatureLengthAvx512_KMASK; + DWORD FeatureLengthAvx512_ZMM_H; + DWORD FeatureLengthAvx512_ZMM; + XmmRegister_t* Sse = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_LEGACY_SSE, &FeatureLengthSse); + XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, &FeatureLengthAvx); + ULONGLONG* Avx512_KMASK = (ULONGLONG*)_LocateXStateFeature(Context, XSTATE_AVX512_KMASK, &FeatureLengthAvx512_KMASK); + ZmmRegister_t* Avx512_ZMM = (ZmmRegister_t *)_LocateXStateFeature(Context, XSTATE_AVX512_ZMM, &FeatureLengthAvx512_ZMM); + YmmRegister_t* Avx512_ZMM_H = (YmmRegister_t *)_LocateXStateFeature(Context, XSTATE_AVX512_ZMM_H, &FeatureLengthAvx512_ZMM_H); + + if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthSse / sizeof(XmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + Sse[i] = titcontext->ZmmRegisters[i].Low.Low; + } + + if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx / sizeof(XmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + Avx[i] = titcontext->ZmmRegisters[i].Low.High; + } + + if (Avx512_ZMM_H != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_ZMM_H / sizeof(YmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + Avx512_ZMM_H[i] = titcontext->ZmmRegisters[i].High; + } + + if (Avx512_ZMM != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_ZMM / sizeof(ZmmRegister_t), _countof(titcontext->ZmmRegisters) - FeatureLengthAvx / sizeof(XmmRegister_t)); i++) + Avx512_ZMM[i] = titcontext->ZmmRegisters[i + FeatureLengthAvx / sizeof(XmmRegister_t)]; + } + + if (Avx512_KMASK != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_KMASK / sizeof(ULONGLONG), _countof(titcontext->Opmask)); i++) + Avx512_KMASK[i] = titcontext->Opmask[i]; + } + + return (SetThreadContext(hActiveThread, Context) == TRUE); +} + +static bool GetAVX512ContextFallbackToAVX(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) +{ + // Fall back to using AVX and fill the rest with 0 + TITAN_ENGINE_CONTEXT_t Avx; + memset(&Avx, 0, sizeof(Avx)); + if (GetAVXContext(hActiveThread, &Avx)) { + for (int i = 0; i < _countof(Avx.YmmRegisters); i++) + titcontext->ZmmRegisters[i].Low = Avx.YmmRegisters[i]; + return true; + } + else { + return false; + } +} + +__declspec(dllexport) bool TITCALL GetAVX512Context(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_AVX512_t* titcontext) +{ + if (InitXState() == false) + return false; + + DWORD64 FeatureMask = _GetEnabledXStateFeatures(); + if ((FeatureMask & XSTATE_MASK_AVX512) == 0) //XSTATE_MASK_AVX512 + return GetAVX512ContextFallbackToAVX(hActiveThread, titcontext); + + DWORD ContextSize = 0; + BOOL Success = _InitializeContext(NULL, + CONTEXT_ALL | CONTEXT_XSTATE, + NULL, + &ContextSize); + + if ((Success == TRUE) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + return false; + + std::vector dataBuffer(ContextSize); + + PCONTEXT Context; + Success = _InitializeContext(dataBuffer.data(), + CONTEXT_ALL | CONTEXT_XSTATE, + &Context, + &ContextSize); + if (Success == FALSE) + return false; + + if (_SetXStateFeaturesMask(Context, XSTATE_MASK_AVX | XSTATE_MASK_AVX512) == FALSE) + return GetAVX512ContextFallbackToAVX(hActiveThread, titcontext); + + if (GetThreadContext(hActiveThread, Context) == FALSE) + return false; + + if (_GetXStateFeaturesMask(Context, &FeatureMask) == FALSE) + return false; + + DWORD FeatureLengthSse; + DWORD FeatureLengthAvx; + DWORD FeatureLengthAvx512_KMASK; + DWORD FeatureLengthAvx512_ZMM_H; + DWORD FeatureLengthAvx512_ZMM; + XmmRegister_t* Sse = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_LEGACY_SSE, &FeatureLengthSse); + XmmRegister_t* Avx = (XmmRegister_t*)_LocateXStateFeature(Context, XSTATE_AVX, &FeatureLengthAvx); + ULONGLONG* Avx512_KMASK = (ULONGLONG*)_LocateXStateFeature(Context, XSTATE_AVX512_KMASK, &FeatureLengthAvx512_KMASK); + ZmmRegister_t* Avx512_ZMM = (ZmmRegister_t *)_LocateXStateFeature(Context, XSTATE_AVX512_ZMM, &FeatureLengthAvx512_ZMM); + YmmRegister_t* Avx512_ZMM_H = (YmmRegister_t *)_LocateXStateFeature(Context, XSTATE_AVX512_ZMM_H, &FeatureLengthAvx512_ZMM_H); + + if (Sse != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthSse / sizeof(XmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + titcontext->ZmmRegisters[i].Low.Low = Sse[i]; + } + + if (Avx != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx / sizeof(XmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + titcontext->ZmmRegisters[i].Low.High = Avx[i]; + } + + if (Avx512_ZMM_H != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_ZMM_H / sizeof(YmmRegister_t), _countof(titcontext->ZmmRegisters)); i++) + titcontext->ZmmRegisters[i].High = Avx512_ZMM_H[i]; + } + + if (Avx512_ZMM != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_ZMM / sizeof(ZmmRegister_t), _countof(titcontext->ZmmRegisters) - FeatureLengthAvx / sizeof(XmmRegister_t)); i++) + titcontext->ZmmRegisters[i + FeatureLengthAvx / sizeof(XmmRegister_t)] = Avx512_ZMM[i]; + } + + if (Avx512_KMASK != NULL) //If the feature is unsupported by the processor it will return NULL + { + for (size_t i = 0; i < MIN(FeatureLengthAvx512_KMASK / sizeof(ULONGLONG), _countof(titcontext->Opmask)); i++) + titcontext->Opmask[i] = Avx512_KMASK[i]; + } + + return true; +} + //PE __declspec(dllexport) bool TITCALL StaticFileLoad(const char* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) { diff --git a/TitanEngineEmulator/TitanEngineEmulator.vcxproj b/TitanEngineEmulator/TitanEngineEmulator.vcxproj index 83f460b..9a288df 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.vcxproj +++ b/TitanEngineEmulator/TitanEngineEmulator.vcxproj @@ -21,31 +21,32 @@ {2790D540-B51E-48F1-B8E9-F14F2EEAA676} TitanEngineEmulator + 10.0 DynamicLibrary true - v140_xp + v141_xp MultiByte DynamicLibrary true - v140_xp + v141_xp MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte DynamicLibrary false - v140_xp + v141_xp true MultiByte diff --git a/TitanEngineEmulator/ntdll.h b/TitanEngineEmulator/ntdll.h index 5064065..4ca05eb 100644 --- a/TitanEngineEmulator/ntdll.h +++ b/TitanEngineEmulator/ntdll.h @@ -2511,9 +2511,9 @@ typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE]; -#define FLS_MAXIMUM_AVAILABLE 128 -#define TLS_MINIMUM_AVAILABLE 64 -#define TLS_EXPANSION_SLOTS 1024 +#define NTDLL_FLS_MAXIMUM_AVAILABLE 128 +#define NTDLL_TLS_MINIMUM_AVAILABLE 64 +#define NTDLL_TLS_EXPANSION_SLOTS 1024 typedef struct _PEB_LDR_DATA { @@ -2656,7 +2656,7 @@ typedef struct _PEB PVOID* FlsCallback; LIST_ENTRY FlsListHead; PVOID FlsBitmap; - ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; + ULONG FlsBitmapBits[NTDLL_FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)]; ULONG FlsHighIndex; PVOID WerRegistrationData;