Windows Exploit Mitigation Technology – Part 1
In this article we will learn about Windows Exploit Mitigation Technology.
What is Windows Exploit Mitigation?
Windows exploit sequencing has led to the creation of a type of exploit protection mechanism in Windows. Protection against things like buffer overflows, heap overwrites, and the return of crafted exploits have been deployed on the Windows and OS compilers.
These can be operating system-specific protections or compiler-based protections. EMET can be used to apply some of these protections to Windows binaries.
According to Microsoft:
“The Enhanced Mitigation Experience Toolkit (EMET) is a tool that helps prevent successful exploitation of vulnerabilities in software. EMET achieves this goal by using security mitigation technologies. These technologies act as special protections and obstacles that an exploit author must overcome in order to exploit software vulnerabilities. These mitigation technologies do not guarantee that vulnerabilities cannot be exploited. However, they are working to make exploitation as difficult as possible.”
The compiler protections included in MSVC are:
[plain]
/GF enable read-only string pooling /Gm[-] enable minimal rebuild
/Gy[-] separate functions for linker /GS[-] enable security checks
/GR[-] enable C++ RTTI /GX[-] enable C++ EH (same as /EHsc)
/EHs enable C++ EH (no SEH exceptions) /EHa enable C++ EH (w/ SEH exceptions)
/EHc extern “C” defaults to nothrow
/Qfast_transcendentals generate inline FP intrinsics even with /fp:except
/GL[-] enable link-time code generation /GA optimize for Windows Application
/Ge force stack checking for all funcs /Gs[num] control stack checking calls
/Gh enable _penter function call /GH enable _pexit function call
/GT generate fiber-safe TLS accesses /RTC1 Enable fast checks (/RTCsu)
/RTCc Convert to smaller type checks /RTCs Stack Frame runtime checking
/RTCu Uninitialized local usage checks
/clr[:option] compile for common language runtime, where option is:
pure – produce IL-only output file (no native executable code)
safe – produce IL-only verifiable output file
oldSyntax – accept the Managed Extensions syntax from Visual C++ 2002/2003
initialAppDomain – enable initial AppDomain behavior of Visual C++ 2002
noAssembly – do not produce an assembly
/Gd __cdecl calling convention /Gr __fastcall calling convention
/Gz __stdcall calling convention /GZ Enable stack checks (/RTCs)
/QIfist[-] use FIST instead of ftol()
/hotpatch ensure function padding for hotpatchable images
/arch:<SSE|SSE2|AVX> minimum CPU architecture requirements, one of:
SSE – enable use of instructions available with SSE enabled CPUs
SSE2 – enable use of instructions available with SSE2 enabled CPUs
AVX – enable use of Intel(R) Advanced Vector Extensions instructions
/Qimprecise_fwaits generate FWAITs only on “try” boundaries, not inside “try”
/Qsafe_fp_loads generate safe FP loads
[/plain]
So it makes exploitation difficult but does not ultimately protect against it.
Stack-Based OverRun Detection (GS)
This is the oldest and best-known protection available in Visual C++. The purpose of the /GS compiler flag is simple: to reduce the likelihood that malicious code will execute correctly. The /GS option is on by default in Visual C++ 2003 and later and detects certain kinds of stack breakage at runtime.
The trick is that you put an invalid number on the function stack just before the return address on the stack, and when the function returns, the function’s epilogue code checks that value to make sure no transmutation occurred. If the cookie, as it is called, has been mutated, execution stops.
Thus, the GS stack cookie basically protects against manipulation of return addresses. Now let’s see how it works in detail:
Consider the following C code compiled using the /GS parameter of the Microsoft C compiler:
{c]
#include
void vuln()
{
unsigned char x[10] = {0};
int i = 0;
while (i != 100)
x[i++] = ‘A’;
}
int main(int argc, char **agrv)
{
vuln();
}
[/c]
If we compile it using MSVC switch /GS it would get the GS stack-based protection embedded. Let’s see what is added at the vuln function for GS stack protection.

Stack Cookie Resides soon after Saved EBP i.e EBP-4 as shown in the IDA disassembly:

As you can see at the beginning of the function prolog, __security_cookie is loaded and xored by EBP. So if the attacker had to overwrite the return address, he has to guess the __security_cookie as clearly as we can clearly see that it will also be overwritten. Now let’s see how it is generated and whether it contains enough randomness to be secure.
This value is generated in the ___security_init_cookie() function, which looks like this:
[plain]
___security_init_cookie proc near ; CODE XREF: $LN26#p
.text:0040267F
.text:0040267F PerformanceCount= LARGE_INTEGER ptr -10h
.text:0040267F SystemTimeAsFileTime= _FILETIME ptr -8
.text:0040267F
.text:0040267F mov edi, edi
.text:00402681 push ebp
.text:00402682 mov ebp, esp
.text:00402684 sub esp, 10h
.text:00402687 mov eax, ___security_cookie
.text:0040268C and [ebp+SystemTimeAsFileTime.dwLowDateTime], 0
.text:00402690 and [ebp+SystemTimeAsFileTime.dwHighDateTime], 0
.text:00402694 push ebx
.text:00402695 push edi
.text:00402696 mov edi, 0BB40E64Eh
.text:0040269B mov ebx, 0FFFF0000h
.text:004026A0 cmp eax, edi
.text:004026A2 jz short loc_4026B1
.text:004026A4 test ebx, eax
.text:004026A6 jz short loc_4026B1
.text:004026A8 not eax
.text:004026AA mov dword_408004, eax
.text:004026AF jmp short loc_402716
.text:004026B1 ; —————————————————————————
.text:004026B1
.text:004026B1 loc_4026B1: ; CODE XREF: ___security_init_cookie+23#j
.text:004026B1 ; ___security_init_cookie+27#j
.text:004026B1 push esi
.text:004026B2 lea eax, [ebp+SystemTimeAsFileTime]
.text:004026B5 push eax ; lpSystemTimeAsFileTime
.text:004026B6 call ds:GetSystemTimeAsFileTime
.text:004026BC mov esi, [ebp+SystemTimeAsFileTime.dwHighDateTime]
.text:004026BF xor esi, [ebp+SystemTimeAsFileTime.dwLowDateTime]
.text:004026C2 call ds:GetCurrentProcessId
.text:004026C8 xor esi, eax
.text:004026CA call ds:GetCurrentThreadId
.text:004026D0 xor esi, eax
.text:004026D2 call ds:GetTickCount
.text:004026D8 xor esi, eax
.text:004026DA lea eax, [ebp+PerformanceCount]
.text:004026DD push eax ; lpPerformanceCount
.text:004026DE call ds:QueryPerformanceCounter
.text:004026E4 mov eax, dword ptr [ebp+PerformanceCount+4]
.text:004026E7 xor eax, dword ptr [ebp+PerformanceCount]
.text:004026EA xor esi, eax
.text:004026EC cmp esi, edi
.text:004026EE jnz short loc_4026F7
.text:004026F0 mov esi, 0BB40E64Fh
.text:004026F5 jmp short loc_402707
.text:004026F7 ; —————————————————————————
.text:004026F7
.text:004026F7 loc_4026F7: ; CODE XREF: ___security_init_cookie+6F#j
.text:004026F7 test ebx, esi
.text:004026F9 jnz short loc_402707
.text:004026FB mov eax, esi
.text:004026FD or eax, 4711h
.text:00402702 shl eax, 10h
.text:00402705 or esi, eax
.text:00402707
.text:00402707 loc_402707: ; CODE XREF: ___security_init_cookie+76#j
.text:00402707 ; ___security_init_cookie+7A#j
.text:00402707 mov ___security_cookie, esi
.text:0040270D not esi
.text:0040270F mov dword_408004, esi
.text:00402715 pop esi
.text:00402716
.text:00402716 loc_402716: ; CODE XREF: ___security_init_cookie+30#j
.text:00402716 pop edi
.text:00402717 pop ebx
.text:00402718 leave
.text:00402719 retn
.text:00402719 ___security_init_cookie endp
[/plain]
Firstly, it will compare __security_cookie with the default value:
[plain]
mov edi, 0BB40E64Eh
mov ebx, 0FFFF0000h
[/plain]
And if matched it will continue to generate a random one. The random value for __security_cookie is generated as a combination of xors for time, processid, threadid, tickcount and QueryPerformanceCounter() values.
And then xored and multiplied.
[plain]
or eax, 4711h
shl eax, 10h
[/plain]
In the epilogue of a function protected by GS stack cookie you will see a call to __security_check_cookie() function which verifies the __security_cookie, and if it is manipulated the process terminates. So done in this way before returning to the attacker controlled area which leverages ret instruction is prevented.

SAFESEH
SAFESEH was added from Windows XP Sp2. It is an operating system protection technique that we can use to protect against SEH overwriting. This technique is not available on 64-bit systems because 64-bit Windows uses a different exception handling mechanism that is very similar to the one used on SAFESEH.
A binary is protected by SAFESEH only if it is explicitly mentioned in the PE header. We can use Microsoft’s Dumpbin tool to check for the existence of this header using the following command line:
[plain]
dumpbin sample.exe /LOADCONFIG
File Type: EXECUTABLE IMAGE
Section contains the following load config:
00000048 size
0 time date stamp
0.00 Version
0 GlobalFlags Clear
0 GlobalFlags Set
0 Critical Section Default Timeout
0 Decommit Free Block Threshold
0 Decommit Total Free Threshold
00000000 Lock Prefix Table
0 Maximum Allocation Size
0 Virtual Memory Threshold
0 Process Heap Flags
0 Process Affinity Mask
0 CSD Version
0000 Reserved
00000000 Edit list
00408310 Security Cookie
00407840 Safe Exception Handler Table
3 Safe Exception Handler Count
[/plain]
Safe Exception Handler Table
Address
——–
00402390
00403FD0
00405040
When an exception occurs, the exception is passed to the SAFESEH handler in ntdll.dll and checks to see if the target of the exception is present in the SAFESEH list. The following is the implementation of RtlCaptureImageExceptionValues on Windows XP sp2.
If the target address is not present in the list, RtlCallKernel32UnhandledExceptionFilter is called to terminate the program.
Related article:Getting started with ethical hacking Complete Guide By Blackhat Pakistan 2023