| Как написать драйвер, работающий во всех NTЗачем ?А затем, что это imho способствует популярности и облегчает поддержку продукта.
  Лично мне очень нравятся программы,
  которые ставятся и работают где угодно. И наоборот, очень раздражают те, что требуют определенного ServicePack,
  имеют отдельный дистрибутив под каждую ОС и т.п. И, вопреки распространенному мнению, сделать драйвер
  универсальным не так сложно.
   Как ?
  Выяснить, где мы находимся. (пример 1)
  Пользуясь знанием версии ОС сделать
    
      хитрые union'ы для структур, которые по-разному объявлены в разных версиях. (пример 2)
      несколько веток if/else для специфичных кусков кода, например инициализация в
       Legacy и WDM стиле. (пример 3)
    Где можно - обходиться без использования "новых" функций
  Где нельзя или очень хочется -
    
 ПримерыЧасть приведенного кода взята из реальных проектов, в частности из DbgPrint Dump,
  а точнее - его библиотеки Cross-Nt (раньше было в SDK, теперь есть и отдельно),
  другая часть героически добыта DeathSoft'ом
  из новых виндов. Есть мысль собрать это все в статические и динамические библиотеки, уже частично реализована в
  Cross-Nt library.
   Example 1Определяем в DriverEntry() версию ОС и готовимся к использованию
  GetModuleHandle()/GetProcAddress(). Если поддержка NT 3.51 не планируется,
  то лучше для поиска загруженых модулей пользоваться NtQuerySystemInformation(), т.к. сканирование
  цепочки LDR_DATA_TABLE_ENTRY во время выгрузки какого-нибудь модуля может увалить систему.
   
    if(!NT_SUCCESS(status = CrNtInit(SavedDriverObject, RegistryPath))) {
        return status;
    }
    CrNtPsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, &SavedSPString);
 
NTSTATUS
CrNtInit(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
{
    PLIST_ENTRY Next;
    PLIST_ENTRY LoadOrderListHead;
    PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    PLDR_DATA_TABLE_ENTRY LdrDataTableEntry0;
    __try
    {
        if(!g_LoadOrderListHead) {
            LdrDataTableEntry0 = (PLDR_DATA_TABLE_ENTRY)DriverObject->DriverSection;
            if(LdrDataTableEntry0) {
                Next = LdrDataTableEntry0->LoadOrder.Blink;
                while (TRUE) {
                    LdrDataTableEntry = CONTAINING_RECORD( Next,
                                                           LDR_DATA_TABLE_ENTRY,
                                                           LoadOrder
                                                         );
                    __try {
                        Next = Next->Blink;
                    } __except(EXCEPTION_EXECUTE_HANDLER) {
                        return STATUS_UNSUCCESSFUL;
                    }
                    if(!LdrDataTableEntry->ModuleName.Buffer) {
                        return STATUS_UNSUCCESSFUL;
                    }
                    __try {
                        if(RtlCompareUnicodeString(&LdrDataTableEntry->ModuleName, &g_NtoskrnlNameString, TRUE) == 0)
                        {
                            LoadOrderListHead = Next;
                            break;
                        }
                    } __except(EXCEPTION_EXECUTE_HANDLER) {
                    }
                    if(LdrDataTableEntry == LdrDataTableEntry0) {
                        return STATUS_UNSUCCESSFUL;
                    }
                }
                g_LoadOrderListHead = LoadOrderListHead;
            } else {
                // We are called from boot-driver, DriverSection is NULL :(
                PVOID p;
                // Locate NTOSKRNL.EXE
                p = (PVOID)&NtBuildNumber;
                g_hNtosKrnl = CrNtFindModuleBaseByPtr(p, "NtBuildNumber");
                // Locate HAL.DLL
                p = (PVOID)HalDisplayString;
                p = CrNtSkipImportStub(p);
                g_hHal = CrNtFindModuleBaseByPtr(p, "HalDisplayString");
            }
        }
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
    }
    if(!g_hNtosKrnl) {
        g_hNtosKrnl = CrNtGetModuleBase("NTOSKRNL.EXE");
    }
    /*
        Init pointers to required functions here.
        Make them pointing either to native implementation or
        to our own stub like this:
        p = CrNtGetProcAddress(g_hNtosKrnl, "PsGetVersion");
        CrNtPsGetVersion = p ? p : PsGetVersion_nt351_impl;
    */
    g_CmCSDVersionString.Buffer = L"";
    g_CmCSDVersionString.Length = 0;
    g_CmCSDVersionString.MaximumLength = 0;
    return STATUS_SUCCESS;
} // end CrNtInit()
Example 2
typedef struct _HW_INITIALIZATION_DATA_COMMON {
  HW_INITIALIZATION_DATA      comm;
  HW_INITIALIZATION_DATA_2K   w2k;
}HW_INITIALIZATION_DATA_COMMON, *PHW_INITIALIZATION_DATA_COMMON;
Example 3
    // Set PnP-specific API
    if(WinVer_Id() > WinVer_NT) {
        hwInitializationData.w2k.HwAdapterControl = AtapiAdapterControl;
    }
 
extern ULONG  MajorVersion;
extern ULONG  MinorVersion;
extern ULONG  BuildNumber;
extern ULONG  SPVersion;
#define WinVer_Is351  (MajorVersion==0x03)
#define WinVer_IsNT   (MajorVersion==0x04)
#define WinVer_Is2k   (MajorVersion==0x05 && MinorVersion==0x00)
#define WinVer_IsXP   (MajorVersion==0x05 && MinorVersion==0x01)
#define WinVer_IsdNET (MajorVersion==0x05 && MinorVersion==0x02)
#define WinVer_Id()   ((MajorVersion << 8) | MinorVersion)
#define WinVer_351    (0x0351)
#define WinVer_NT     (0x0400)
#define WinVer_2k     (0x0500)
#define WinVer_XP     (0x0501)
#define WinVer_dNET   (0x0502)
 Example 4
    p = CrNtGetProcAddress(g_hNtosKrnl, "PsGetVersion");
    CrNtPsGetVersion = p ? p : PsGetVersion_nt351_impl;
    if(WinVer_Id() > WinVer_NT) {
        IoGetAttachedDeviceReference = (PIO_GET_ATTACHED_DEVICE_REFERENCE)
            CrNtGetProcAddress(g_hNtosKrnl, "IoGetAttachedDeviceReference");
        PoStartNextPowerIrp = (PPO_START_NEXT_POWER_IRP)
            CrNtGetProcAddress(g_hNtosKrnl, "PoStartNextPowerIrp");
        PoCallDriver = (PPO_CALL_DRIVER)CrNtGetProcAddress(g_hNtosKrnl, "PoCallDriver");
    }
Код "новых" функцийby DeathSoft
 
ULONG
inline
ObGetObjectPointerCount(
    IN PVOID Object
    )
{
    POBJECT_HEADER Hdr=OBJECT_TO_OBJECT_HEADER(Object);
    return Hdr->PointerCount;
} // end ObGetObjectPointerCount()
 
ULONG
inline
ObGetObjectHandleCount(
    IN PVOID Object
    )
{
    POBJECT_HEADER Hdr=OBJECT_TO_OBJECT_HEADER(Object);
    return Hdr->HandleCount;
} // end ObGetObjectHandleCount()
 
#define OBJECT_TO_OBJECT_HEADER(obj) \
    CONTAINING_RECORD( (obj), OBJECT_HEADER, Body )
typedef struct _OBJECT_HEADER {
    union {
        struct {
            LONG PointerCount;
            LONG HandleCount;
        };
        LIST_ENTRY Entry;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;
    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;
 
#define OBJECT_HEADER_TO_NAME_INFO(ohdr) ((POBJECT_HEADER_NAME_INFO) \
    ((ohdr)->NameInfoOffset == 0 ? NULL : ((PCHAR)(ohdr) - (ohdr)->NameInfoOffset)))
 
BOOLEAN
__fastcall
KeTestSpinLock(
    IN PKSPIN_LOCK SpinLock
    )
{
    if(!*SpinLock)
    {
        return TRUE;
    }
    __asm pause;
    return FALSE;
} // end KeTestSpinLock()
 
__declspec (naked)
HANDLE
CrNtPsGetCurrentProcessId_impl() 
{
    _asm {
        mov eax,fs:[124h]
        mov eax,[eax+1e0h]
        ret
    }
}
 
__declspec (naked)
HANDLE
CrNtPsGetCurrentThreadId_impl() 
{
    _asm {
        mov eax,fs:[124h]
        mov eax,[eax+1e4h]
        ret
    }
}
См. также
     |