A Debugging Approach to IFEO

IFEO (Image File Execution Options) is a feature provided by the NT based operating system. It can be helpful when you are trying to debug at the very beginning of an application launch. A few people also taked about IFEO on MSDN Blogs:

  1. Image File Execution Options by Junfeng.
  2. Inside 'Image File Execution Options' debugging by Gregg.
  3. Beware the Image File Execution Options key by Raymond.
  4. IFEO and Managed-debugging by Mike.

Debugger (REG_SZ)

Let's begin with the following demo (I'm using 32bit Win7, you might see different things if you are using other version of Windows):

 #define WIN32_LEAN_AND_MEAN

#include <Windows.h>

#define IfFalseRet(c) do{if(!(c)){return dwLastError = GetLastError();}}while(0)

STARTUPINFO g_startupInfo = {sizeof(STARTUPINFO)};
TCHAR g_szCommandLine[] = TEXT("notepad.exe");

int WINAPI ExeEntry(void)

  PROCESS_INFORMATION processInformation;
  IfFalseRet(CreateProcess(NULL, g_szCommandLine, NULL, NULL, FALSE, 0,
                           NULL, NULL, &g_startupInfo, &processInformation));

  return dwLastError;

To compile the source code, you may use Visual Studio Command Prompt (x86):

cl.exe createprocess.c /D UNICODE /GS- /Od /Oy /link /ENTRY:ExeEntry /NODEFAULTLIB /OPT:ICF /OPT:REF /RELEASE /SUBSYSTEM:CONSOLE kernel32.lib

Now with the Process Monitor opened, launch the demo, and you should be able to find the following record captured by Process Monitor:

00:01:17.8231352 createprocess.exe 1320 RegOpenKey HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe NAME NOT FOUND Desired Access: Query Value, Enumerate Sub Keys

Let's create an IFEO entry in the registry:

 Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe]
"Debugger"="\"C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe\""

After the IFEO entry got imported to the registry, launch the demo again and you will see notepad.exe was replaced by wordpad.exe, with the string "notepad.exe" passed in as an argument.

00:24:32.3322232 createprocess.exe 4668 RegQueryValue HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\New Key #1\Debugger SUCCESS Type: REG_SZ, Length: 108, Data: "C:\Program Files\Windows NT\Accessories\wordpad.exe"

00:24:32.3343642 createprocess.exe 4668 Process Create C:\Program Files\Windows NT\Accessories\wordpad.exe SUCCESS PID: 2724, Command line: "C:\Program Files\Windows NT\Accessories\wordpad.exe" notepad.exe

Let's launch the demo application from WinDBG:

windbg.exe createprocess.exe

0:000> x *!*Create*Process*
767007a2 kernel32!CreateProcessInternalW
766b2082 kernel32!CreateProcessA
766b204d kernel32!CreateProcessW
7670c89c kernel32!CreateProcessInternalA
77d756a8 ntdll!NtCreateProcessEx
77d75698 ntdll!NtCreateProcess
77d889fb ntdll!RtlpCreateProcessRegistryInfo
77d75698 ntdll!ZwCreateProcess
77d756a8 ntdll!ZwCreateProcessEx
77d56bdf ntdll!RtlpCreateUserProcess
77d56b71 ntdll!RtlCreateUserProcess
77dd1072 ntdll!RtlCreateProcessReflection
77d75778 ntdll!ZwCreateUserProcess
77dd988a ntdll!RtlCreateProcessParameters
77d75778 ntdll!NtCreateUserProcess
77d96ee9 ntdll!RtlCreateProcessParametersEx

0:000> bp kernel32!CreateProcessInternalW

0:000> g
Breakpoint 0 hit

0:000> k3
ChildEBP RetAddr
0018f7a8 7670c9bf kernel32!CreateProcessInternalW
0018f888 766b20ae kernel32!CreateProcessInternalA+0x2f8
0018f8c0 00d71068 kernel32!CreateProcessA+0x2c

0:000> ddu esp L6
0018f7ac 7670c9bf "???..?"
0018f7b0 00000000
0018f7b4 00000000
0018f7b8 00383a08 "notepad.exe"
0018f7bc 00000000
0018f7c0 00000000

Continue tracing, eventually we will reach this point:

ChildEBP RetAddr
001af248 77d75784 ntdll!KiFastSystemCall
001af24c 76700eff ntdll!NtCreateUserProcess+0xc
001af8a8 7670c9bf kernel32!CreateProcessInternalW+0xe75
001af988 766b20ae kernel32!CreateProcessInternalA+0x2f8
001af9c0 01371068 kernel32!CreateProcessA+0x2c

0:000> bp 77d75784
0:000> g
Breakpoint 1 hit

From Process Monitor we can trace the IFEO registry key access from kernel mode. On my Win7 machine, it showed three operations (RegOpenKey, RegQueryValue, RegQueryValue), this is because IFEO was moved into kernel mode since Longhorn. On Windows XP and Windows Server 2003, IFEO is a pure user mode action, which means you can easily bypass it without having to write a kernel mode driver. Another thing is, kernel mode IFEO doesn't have the bitness problem, as it would never read from Wow6432Node.

Continue tracing until we have the following call stacks:

ChildEBP RetAddr
0020efe4 77d9ce6f ntdll!RtlQueryImageFileExecutionOptions
0020f008 76704ab1 ntdll!LdrQueryImageFileExecutionOptions+0x1e
0020f034 76702abb kernel32!BasepGetDisableLocalOverrideConfig+0x33
0020f0ac 7670119b kernel32!BasepConstructSxsCreateProcessMessage+0x8e
0020f728 7670c9bf kernel32!CreateProcessInternalW+0x16b1
0020f808 766b20ae kernel32!CreateProcessInternalA+0x2f8
0020f840 01371068 kernel32!CreateProcessA+0x2c

ChildEBP RetAddr
001af264 7672d529 kernel32!BuildSubSysCommandLine
001af8a8 7670c9bf kernel32!CreateProcessInternalW+0xf87
001af988 766b20ae kernel32!CreateProcessInternalA+0x2f8
001af9c0 01371068 kernel32!CreateProcessA+0x2c

0:000> ddu esp L6
001af268 7672d529 "??????"
001af26c 00000003
001af270 00234348 ""C:\Program Files\Windows NT\Accessories\wordpad.exe""
001af274 00000000
001af278 00233a08 "notepad.exe"
001af27c 001af4d8 ".."

Continue tracing:

ChildEBP RetAddr
001af1ac 76701693 ntdll!RtlCreateProcessParametersEx
001af258 76700e90 kernel32!BasepCreateProcessParameters+0x148
001af8a8 7670c9bf kernel32!CreateProcessInternalW+0xe06
001af988 766b20ae kernel32!CreateProcessInternalA+0x2f8
001af9c0 01371068 kernel32!CreateProcessA+0x2c

0:000> dS poi(esp+8)
00283cf8 "C:\Program Files\Windows NT\Acce"
00283d38 "ssories\wordpad.exe"

Continue tracing:

ChildEBP RetAddr
001af24c 76700eff ntdll!NtCreateUserProcess
001af8a8 7670c9bf kernel32!CreateProcessInternalW+0xe75
001af988 766b20ae kernel32!CreateProcessInternalA+0x2f8
001af9c0 01371068 kernel32!CreateProcessA+0x2c

Now the user mode IFEO logic looks clear to us, let's restart WinDBG and do some tweaking:

0:000> .restart
0:000> bp kernel32!BuildSubSysCommandLine; g; bc
Breakpoint 0 hit

0:000> ezu poi(esp+8) "calc.exe"

0:000> g

As you could see, Calculator is launched instead of WordPad.

VerifierDlls (REG_SZ)

VerifierDlls is a list of verifier provider DLLs used by the AppVerifier. The NT loader consumes VerifierDlls during user mode process initialization, which happens in ntdll!LdrpInitializeProcess. If VerifierDlls was found, the standard verifier provider verifier.dll, which comes with the Windows system, will be loaded first. After that, each verifier provider specified by VerifierDlls will be loaded one by one:

ChildEBP RetAddr
0020f37c 7719578b ntdll!AVrfpLoadAndInitializeProvider+0x117
0020f3a0 77170bd9 ntdll!AVrfInitializeVerifier+0xd3
0020f518 77156077 ntdll!LdrpInitializeProcess+0xe95
0020f568 77153663 ntdll!_LdrpInitialize+0x78
0020f578 00000000 ntdll!LdrInitializeThunk+0x10

771950e1 push 1Ch
771950e3 push offset ntdll! ?? ::FNODOBFM::`string'+0x762 (77140ed8)
771950e8 call ntdll!_SEH_prolog4 (77142c0c)
771950ed mov byte ptr [ebp-19h],0
771950f1 mov esi,dword ptr [ebp+8]
771950f4 test byte ptr [ntdll!AVrfpDebug (771ce380)],1
771950fb je ntdll!AVrfpLoadAndInitializeProvider+0x2b (7719510c)
771950fd push dword ptr [esi+0Ch]
77195100 push offset ntdll! ?? ::FNODOBFM::`string' (7713a708)
77195105 call ntdll!DbgPrint (7710f593)
7719510a pop ecx
7719510b pop ecx
7719510c mov dword ptr [ebp-28h],offset ntdll!RtlpCsVerifyDoNotBreak+0x7 (771ce178)
77195113 xor eax,eax
77195115 mov word ptr [ebp-2Ch],ax
77195119 mov eax,208h
7719511e mov word ptr [ebp-2Ah],ax
77195122 push offset SharedUserData+0x30 (7ffe0030)
77195127 lea eax,[ebp-2Ch]
7719512a push eax
7719512b call ntdll!RtlAppendUnicodeToString (7714eed2)
77195130 push offset ntdll!SlashSystem32SlashString (771551f0)
77195135 lea eax,[ebp-2Ch]
77195138 push eax
77195139 call ntdll!RtlAppendUnicodeStringToString (771472be)
7719513e lea ebx,[esi+10h]
77195141 push ebx
77195142 lea eax,[esi+8]
77195145 push eax
77195146 push 0
77195148 push dword ptr [ebp-28h]
7719514b call ntdll!LdrLoadDll (771522b8)
77195150 test eax,eax
77195152 jge ntdll!AVrfpLoadAndInitializeProvider+0x98 (77195179)
77195154 push dword ptr [ebp-28h]
77195157 push eax
77195158 push dword ptr [esi+0Ch]
7719515b mov eax,dword ptr [ntdll!PebLdr+0xc (771c788c)]
77195160 ff7030 push dword ptr [eax+30h]
77195163 push offset ntdll! ?? ::FNODOBFM::`string' (7713a6c6)
77195168 call ntdll!DbgPrint (7710f593)
7719516d add esp,14h
77195170 mov byte ptr [ebp-19h],1
77195174 jmp ntdll!AVrfpLoadAndInitializeProvider+0x21c (771952fd)
77195179 and dword ptr [ebp-4],0
7719517d push dword ptr [ebx]
7719517f call ntdll!RtlImageNtHeader (7714fa29)
77195184 mov edi,eax

The AppVerifier package comes with a GUI frontend, together with a stack of verifier providers. A verifier provider is a special DLL which accepts DLL_PROCESS_VERIFIER. The WinNT.h header file in DDK 3790.1830 contains everything needed for implementing a verifier provider.

 #define WIN32_LEAN_AND_MEAN
#include <Windows.h>
static RTL_VERIFIER_DLL_DESCRIPTOR aDlls[] = {{}};

  if(fdwReason == DLL_PROCESS_VERIFIER)
    *pVPD = &vpd;
  return TRUE;

You can read A Debugging Approach to Application Verifier for more information.


DisableExceptionChainValidation (REG_DWORD)

SEHOP (Structured Exception Handling Overwrite Protection) is a feature introduced by Windows Vista SP1 to protect a certain kind of attack. However this feature would cause compatibility issues to some existing applications, so the purpose of this value is to workaround for legacy applications by disabling SEHOP feature.

(to be continued...)