An x64 Win10 ported driver works properly on Win8.1, but doesn’t on Win7.
Consider a .data section like this:
Virtual address: 10008D00 Raw size: 100h Virtual size: 200h
In the code below, right at DriverEntry, RtlGetVersion fails, driver fails to load with Error 37:
1 2
mov cs:dword_10008D00, 11Ch -> sets dwOSVersionInfoSize for RTL_OSVERSIONINFOEXW call cs:RtlGetVersion
So I did the following test, to see if data can be written to address higher than 10008E00 and driver also fails to load with Error 37:
1
mov cs:dword_10008E10, 1Ch
Basically, data cannot be written to address above raw size 10008E00 (10008D00 + 100h).
NOP'ing RtlGetVersion allows the driver to load, but it won't work properly because of missing structures/data supposed to be created at addresses higher than 10008E00.
Nothing wrong with any section flags.
Have you ever seen this? Please shine some light on this.
I need the driver file in order to debug this, otherwise I cannot say what the cause is.
I have produced an x64 driver with the exact same raw and virtual .data section sizes specified above (and the variable to be written to at +0x100 from the start of .data), and I cannot reproduce this. The driver loads with no issues on both Win 7 and 10 (I didn’t test on 8.1, but I think we can assume that 8.1 and 10 will behave the same here).
Some things I could think of that might influence this: - The value of FileAlignment in the PE optional header. Is it 0x200 (default), or (highly unlikely) 0x100? I tried to test if this matters, but signtool.exe refuses to sign drivers with a FileAlignment less than 0x200, and if you attempt to load the (unsigned) driver anyway, then both Windows 7 and 10 will refuse to load it. - The value of SizeOfUninitializedData in the PE optional header. Is it 0 or 0x100 (excluding the count from any other potential sections containing uninitialized data)? - The section characteristics of .data. What is the value, and in particular, is the ‘contains uninitialized data’ flag set? (Normal values: 0xC8000040 if .data does not contain uninitialized data, 0xC80000C0 if it does.) - Is the raw address of .data (‘PointerToRawData’) aligned to a multiple of 0x200 or only 0x100? Same question for the section following .data (usually .pdata). - Is the ‘code integrity image’ flag (produced by linking with /INTEGRITYCHECK) set in the DllCharacteristics of the PE optional header? (IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 0x80, if this is included then this is a code integrity image.)
I tested all of the above by changing them to values ranging from ‘technically incorrect’ to straight out invalid values/combinations (e.g. setting ‘contains unintialized data’ on .data but having a SizeOfUninitalizedData of 0, and so on). I could not get my driver to fail to load on either 7 or 10 no matter what. The only exception is the above noted case of FileAlignment = 0x100, which I believe is simply not allowed by any version of Windows. I did expect that under-aligning the raw address of .data or .pdata would cause a load failure, but apparently the kernel does not care about this.
In short, I believe there is probably something about the PE file that makes it technically invalid in a way that matters to the Windows 7 kernel but not the 8.1/10 one. To see what this is exactly I will need the file in order to examine it and step through the driver load with a debugger.
By the way, a side note: Win32 errors returned by sc.exe, like the ‘error 37’ which you mentioned, are meaningless and do not convey any useful information. The reason Win32 errors are useless is because converting an NTSTATUS (the return value of the driver load attempt) to a Win32 error is a process that throws away nearly all of the information encoded in the NTSTATUS and replaces it with a generic error like ‘access denied’ or ‘invalid parameter’. What you actually want when diagnosing a driver load failure is the NTSTATUS returned by the NtLoadDriver system call. You can look up the names and detailed descriptions of these values in ntstatus.h (part of the Windows SDK/DDK).