Monday, December 26, 2016

NT 4.0, .NET 1.1, and INTLFXSR.SYS problems

Here is the code from a disassembly of INTLFXSR.SYS with symbols:
.text:000102A0 ; __stdcall FxsrGetProcessorFeatures()
.text:000102A0                 public _FxsrGetProcessorFeatures@0
.text:000102A0 _FxsrGetProcessorFeatures@0 proc near   ; CODE XREF: DriverEntry(x,x)+61 p
.text:000102A0                 push    edi
.text:000102A1                 push    esi
.text:000102A2                 push    ebx
.text:000102A3                 pushf
.text:000102A4                 pop     eax
.text:000102A5                 push    eax
.text:000102A6                 mov     ecx, eax
.text:000102A8                 xor     eax, 40000h
.text:000102AD                 push    eax
.text:000102AE                 popf
.text:000102AF                 pushf
.text:000102B0                 pop     eax
.text:000102B1                 cmp     ecx, eax
.text:000102B3                 jz      short cpu_is_i386
.text:000102B5                 mov     eax, ecx
.text:000102B7                 xor     eax, 200000h
.text:000102BC                 push    eax
.text:000102BD                 popf
.text:000102BE                 pushf
.text:000102BF                 pop     eax
.text:000102C0                 cmp     ecx, eax
.text:000102C2                 jz      short other_cpu
.text:000102C4                 mov     eax, 0
.text:000102C9                 cpuid
.text:000102CB                 cmp     eax, 3
.text:000102CE                 jg      short cpu_identified
.text:000102D0                 mov     _VerifyIntel, ebx
.text:000102D6                 mov     dword_106C4, edx
.text:000102DC                 mov     dword_106C8, ecx
.text:000102E2                 lea     esi, _VerifyIntel
.text:000102E8                 lea     edi, _GenuineIntel ; "GenuineIntel"
.text:000102EE                 mov     ecx, 0Ch
.text:000102F3                 repe cmpsb
.text:000102F5                 jnz     short other_cpu
.text:000102F7                 mov     eax, 1
.text:000102FC                 cpuid
.text:000102FE                 mov     eax, edx
.text:00010300                 jmp     short cpu_identified
.text:00010302 ; ---------------------------------------------------------------------------
.text:00010302
.text:00010302 other_cpu:                              ; CODE XREF: FxsrGetProcessorFeatures()+22 j
.text:00010302                                         ; FxsrGetProcessorFeatures()+55 j
.text:00010302                 mov     eax, 0
.text:00010307                 jmp     short cpu_identified
.text:00010309 ; ---------------------------------------------------------------------------
.text:00010309
.text:00010309 cpu_is_i386:                            ; CODE XREF: FxsrGetProcessorFeatures()+13 j
.text:00010309                 mov     eax, 0
.text:0001030E
.text:0001030E cpu_identified:                         ; CODE XREF: FxsrGetProcessorFeatures()+2E j
.text:0001030E                                         ; FxsrGetProcessorFeatures()+60 j ...
.text:0001030E                 popf
.text:0001030F                 pop     ebx
.text:00010310                 pop     esi
.text:00010311                 pop     edi
.text:00010312                 retn
.text:00010312 _FxsrGetProcessorFeatures@0 endp
If you know x86 assembly, you will notice that it relies on a GenuineIntel CPU and for CPUID leaf 0 to return a value less than 3.
As for the .NET Framework 1.1 problems, the way to determine if SSE is supported is to first use CPUID to determine if the SSE bit is set. But there is also an extra step. Without CR4.OSFXSR set, SSE instructions will cause #UD. This can be caught on Windows as a SEH exception. My guess is that .NET 1.1 is not doing that, which is why it crashes without INTLFXSR.SYS properly loaded.