Peter Ferrie mentioned a nice trick in his Anti-Debugging Reference article http://pferrie.host22.com/papers/antidebug.pdf with RtlProcessFlsData. He provided a “cryptic” example code in assembler. Although his example will work, there are a lot of open questions he doesn’t answer. His code is not usable in a productive environment and I wanted to demonstrate this trick with a more readable and solid example. This trick is very undocumented and I couldn’t find any further information with Google. This trick works since Vista. Fiber Local Storage (FLS) is similar to Thread Local storage (TLS), because a thread is created which can be used to execute some hidden stuff.
Let’s start with the function RtlProcessFlsData, the real declaration is unknown, but it must be similar to this:
NTSYSCALLAPI NTSTATUS NTAPI RtlProcessFlsData ( PRTL_UNKNOWN_FLS_DATA Buffer );
The API takes some unknown struct pointer as parameter. The structure must be similar to this:
typedef struct _RTL_UNKNOWN_FLS_DATA { PVOID unk1; PVOID unk2; PVOID unk3; PVOID Argument; } RTL_UNKNOWN_FLS_DATA,*PRTL_UNKNOWN_FLS_DATA;
Only one structure member is relevant for this anti-debug trick. The trick further involves the Process Environment Block (PEB). We must replace two values. Again, the declaration/definition is unknown and not documented.
First we must replace a callback structure inside the PEB. The structure could look like this:
typedef struct _FLS_CALLBACK { PVOID Unknown; PVOID StartAddress; } FLS_CALLBACK, *PFLS_CALLBACK; #define UNKNOWN_MAX_CALLBACKS 5 typedef struct _FLS_CALLBACK_INFO { PVOID Unknown; FLS_CALLBACK Callbacks[UNKNOWN_MAX_CALLBACKS]; } FLS_CALLBACK_INFO, *PFLS_CALLBACK_INFO;
We can define different callback addresses which will be executed one by one. The second PEB manipulation is the number of callbacks we have in our structure.
A working example code for x64 and x86 can look like this:
info.Callbacks[0].StartAddress = ContinueExecution; rtl.unk1 = UnknownReturnBuffer; rtl.unk2 = UnknownReturnBuffer; rtl.unk3 = UnknownReturnBuffer; rtl.Argument = (LPVOID)0x1337; DWORD_PTR pPeb = 0; #ifdef _WIN64 #define PEB_FLS_CALLBACK_OFFSET 0x0320 #define PEB_FLS_NUMBERCALLBACKS_OFFSET 0x0350 pPeb = (DWORD_PTR)__readgsqword(12 * sizeof(DWORD_PTR)); //PEB Address #else #define PEB_FLS_CALLBACK_OFFSET 0x020C #define PEB_FLS_NUMBERCALLBACKS_OFFSET 0x022C pPeb = (DWORD_PTR)__readfsdword(12 * sizeof(DWORD_PTR)); //PEB Address #endif pFlsNumberOfCallbacks = (ULONG *)(pPeb + PEB_FLS_NUMBERCALLBACKS_OFFSET); pFlsCallbackInfo = (DWORD_PTR *)(pPeb + PEB_FLS_CALLBACK_OFFSET); //backup backupFlsNumberOfCallbacks = *pFlsNumberOfCallbacks; backupFlsCallback = *pFlsCallbackInfo; //we have only 1 callback in the struct *pFlsCallbackInfo = (DWORD_PTR)&info; *pFlsNumberOfCallbacks = 1; RtlProcessFlsData(&rtl); //restore everything like nothing happened *pFlsCallbackInfo = backupFlsCallback; *pFlsNumberOfCallbacks = backupFlsNumberOfCallbacks;
We must fill the RTL_UNKNOWN_FLS_DATA structure with the thread argument and some return buffer. In the FLS_CALLBACK_INFO structure we only have to fill in our thread start address. After RtlProcessFlsData, we should restore the original values in the PEB.
Source code and binaries here:
https://bitbucket.org/NtQuery/teststuff/downloads/RtlProcessFlsData.rar
https://bitbucket.org/NtQuery/teststuff/src/bf9561261acb36bf992f0da2ca143d531086aa01/RtlProcessFlsData.cpp?at=master
I’m on a fully updated Windows 8.1 x64
The 32bit version executable does the following effect:
– Messagebox shows up
– After pressing OK, executable crashes
It isn’t happening with the 64bit executable.