Кроссплатформенный драйвер

Тема в разделе "WASM.NT.KERNEL", создана пользователем lukash, 16 сен 2007.

  1. _BC_

    _BC_ БЦ

    Публикаций:
    0
    Регистрация:
    20 янв 2005
    Сообщения:
    759
    lukash
    Насчет динамической загрузки -- официальных, т.е. документированных способов динамически грузить NT-драйвера под 9х (сиречь WDM) вообще нету. Они расчитаны только на статическую загрузку, регистрацией в реестре и копированием в \System -- по аналогии с NT/XP, только с поправкой, что SCM недоступен.

    Недокументированный способ есть, но с нюансами:

    а) нельзя динамически выгрузить (т.е. будет жить до перезагрузки).
    б) зато можно повторно загружать тот же самый драйвер, как бы поверх. ;)
    в) количество таких перезапусков драйвера ограничено -- после n-го их числа винда падает. Сколько точно не помню, что-то порядка десяти.
    г) дурацкое ограничение в ntkern.vxd на путь к драйверу -- он должен быть в \System, поэтому перед манипуляциями надо его туда копировать и соответственно удалять, когда он более не нужен.

    За исключением этих нюансов дин. загрузка WDM на 9х в принципе нормально реализуется.

    Cкачай вышеупомянутого Walter Oney, если еще нет -- там описаны различия между 9x и nt для wdm-драйверов, какие функции недоступны, какие работают несколько иначе и тп.
     
  2. lukash

    lukash New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2006
    Сообщения:
    142
    _BC_

    Спасибо. Книгу скачал, понемногу разбираюсь...

    Смотрел немного твой загрузчик драйвера acpi_off, там ведь как раз так и реализовано, как ты говоришь? :)
    Но ведь там сам драйвер не совсем WDM, или нет, если не секрет?
     
  3. _BC_

    _BC_ БЦ

    Публикаций:
    0
    Регистрация:
    20 янв 2005
    Сообщения:
    759
    WDM -- это по сути самые обычные NT'шные KMD-драйвера. С точки зрения NT, WDM -- всего лишь набор рекомендаций и требований к драйверам. А вот для 9x это уже весьма нечто -- возможность помимо vxd грузить NT'шные драйвера, пусть с кучей ограничений, но тем не менее.
    По докам они "source-level compatible", но реально они и binary-compatible -- если знать, чего надо избегать, чтобы этот драйвер работал и на 9х, и на NT. В первую очередь эта совместимость определяется набором доступных системных функций -- ntkern.vxd реализует далеко не все NT'шные сервисы. Есть утилита, afair от этой самой книжки, которая проверяет драйвер на соответствие WDM, т.е. будет ли он работать и под 9х, и под NT/XP. Она в т.ч. смотрит и на импортируемые драйвером функции.

    Если писать не полноценный драйвер для какой-нть реальной и сложной железки, а так, чисто под свой Ring0-код, то wdm под 9х самое то для плавной миграции с 9x на NT. ;) Особенно когда привык к 9х, знаешь ее ядро, есть привычные инструменты и тп и тд -- а надо делать что-то под NT, которая после 9х вызывает почти суеверный ужас. ;)

    Да, там остался и код для загрузки под 9х. Ща проверил под win98se на вмваре и не без удивления обнаружил, что оно работает и на 9х. Изначально это вообще-то совсем не планировалось. ;) Тем более повезло, что вин9х может (ессно после чтения всей инфы) дискардить ACPI Reclaim Area, в которой располагаются используемые acpi_off таблицы.


    Вот тот самый фрагмент дин. загрузки nt-драйвера под 9x (т.е. из загрузчика off_drv.sys).

    Сначала для драйвера выполняется обычная регистрация, как будто это статик WDM и копирование в SYSTEM, разница, насколько помню, только в поле Start:
    Код (Text):
    1. ;-------------------------------------------------
    2. ; LoadDriver9x -- static wdm drv registration
    3. ;-------------------------------------------------
    4. LoadDriver9x    proc    pDrvName:DWORD, pServName:DWORD
    5.         local   ImagePath:BYTE:256, hkServices:DWORD, hkMyKey:DWORD, \
    6.             shit:DWORD, DestPath:BYTE:256, temp_str:BYTE:256
    7.  
    8.         lea eax, [hkServices]
    9.         push    eax     ; &hkKey
    10.         push    KEY_ALL_ACCESS  ; Access
    11.         push    0       ; reserved
    12.         pushstr 'System\CurrentControlSet\Services' ; lpPath
    13.         push    HKEY_LOCAL_MACHINE
    14.         call    RegOpenKeyExA
    15.  
    16.         lea eax, [shit]
    17.         push    eax     ; &dwDisp
    18.         lea eax, [hkMyKey]  ; &hKey
    19.         push    eax
    20.         push    0
    21.         push    KEY_ALL_ACCESS
    22.         push    REG_OPTION_NON_VOLATILE
    23.         pushstr 0       ; lpClass
    24.         push    0
    25.         push    [pServName]
    26.         push    [hkServices]
    27.         call    RegCreateKeyExA
    28.  
    29.         lea eax, [shit]
    30.         push    eax     ; lpFilePart
    31.         lea eax, [ImagePath]
    32.         push    eax     ; pPathBuf
    33.         push    256
    34.         push    [pDrvName]
    35.         call    GetFullPathNameA
    36.  
    37.         push    4
    38.         pushstr <1,0,0>
    39.         push    REG_DWORD
    40.         push    0
    41.         pushstr 'Type'
    42.         push    [hkMyKey]
    43.         call    RegSetValueExA
    44.  
    45.         push    4
    46.         pushstr <3,0,0>     ; <-- можно менять на нужное
    47.         push    REG_DWORD
    48.         push    0
    49.         pushstr 'Start'
    50.         push    [hkMyKey]
    51.         call    RegSetValueExA
    52.  
    53.         push    4
    54.         pushstr <1,0,0>
    55.         push    REG_DWORD
    56.         push    0
    57.         pushstr 'ErrorControl'
    58.         push    [hkMyKey]
    59.         call    RegSetValueExA
    60.  
    61.         push    4+1
    62.         pushstr 'Base'
    63.         push    REG_SZ
    64.         push    0
    65.         pushstr 'Group'
    66.         push    [hkMyKey]
    67.         call    RegSetValueExA
    68.  
    69.         push    edi
    70.         push    esi
    71.  
    72.         lea eax, [DestPath]
    73.         mov esi, eax
    74.         push    eax
    75.         call    GetSystemDirectoryA, eax, 256
    76.  
    77.         lea edi, [esi+eax]
    78.         mov al, '\'
    79.         stosb
    80.         mov esi, [pDrvName]
    81. add_str1:   lodsb
    82.         cmp al, 0
    83.         stosb
    84.         jnz add_str1
    85.  
    86.         lea edx, [ImagePath]
    87.         pop eax
    88.         call    CopyFile, edx, eax, 0
    89.  
    90.         lea edi, [temp_str]
    91.         mov edx, edi
    92.         AddStr  '\SystemRoot\SYSTEM\'
    93.  
    94.         mov esi, [pDrvName]
    95. add_str2:   lodsb
    96.         cmp al, 0
    97.         stosb
    98.         jnz add_str2
    99.  
    100.         call    strlen, edx
    101.         pop edx
    102.         inc eax
    103.  
    104.         push    eax
    105.         push    edx
    106.         push    REG_SZ
    107.         push    0
    108.         pushstr 'ImagePath'
    109.         push    [hkMyKey]
    110.         call    RegSetValueExA
    111.  
    112.         call    RegCloseKey, [hkMyKey]
    113.         call    RegCloseKey, [hkServices]
    114.  
    115.         pop esi
    116.         pop edi
    117.  
    118.         ret
    119. LoadDriver9x    endp
    120. ;-------------------------------------------------
    Собственно загрузка выглядит вот так:
    Код (Text):
    1. .code
    2. ; Const Data
    3. MyServName  db  SERVICE_NAME
    4. aslashname  db  APP_SYMLINK_NAME
    5. MyServName_uni  dw  str_len-2
    6.         dw  str_len
    7.         dd  offset str
    8.  
    9. str:        unicode 0, %DRIVER_REG_PATH,0
    10. str_len     equ $-str
    11.  
    12.  
    13. ;----------------------------------------------------------------------------
    14. ; WDM dynaload (both 9x and NT/XP)
    15. ;----------------------------------------------------------------------------
    16.         call    GetVersion
    17.         test    eax, eax
    18.         sets    [PlatformID]
    19.         js  _w9x
    20.         ; nt initialization
    21.         push    offset MyServName
    22.         call    UnloadDriverNT  ; just for sure
    23.  
    24.         pushstr SERVICE_DESCRIPTION
    25.         push    offset MyServName
    26.         pushstr DRIVER_FILE_NAME
    27.         call    LoadDriverNT    ; стандартная загрузка NT-драйвера ч/з SCM
    28.         test    eax, eax
    29.         jnz load_drv
    30. err_drv:    FatalMes 'Loading Driver Failed!'
    31. _w9x:       ; w9x initialization
    32.         call    Get_VxDCall
    33.  
    34.         push    offset MyServName
    35.         pushstr DRIVER_FILE_NAME
    36.         call    LoadDriver9x
    37.  
    38. перемещаем unicode-строку с реестровым путем драйвера в System Area,
    39. иначе (с большой долей вероятности) можно нарваться на случайные глюки.
    40. Heil 9x! ;)
    41.         xor eax, eax
    42.         inc eax
    43.         call    Ring0_malloc    ; shouldn't fail
    44.         xchg    edi, eax
    45.         mov edx, edi
    46.  
    47.         mov eax, (str_len SHL 16) + str_len - 2
    48.         stosd
    49.         lea eax, [edx+8]
    50.         stosd
    51.  
    52.         mov esi, offset str
    53.         mov ecx, str_len
    54.         repz    movsb
    55.  
    56. ; собственно загрузка драйвера. Обратной функции к сожалению нету, т.к.
    57. ; wdm под 9x вообще расчитаны только на стат. загрузку
    58.         push    edx
    59.         mov edx, esp
    60.         mov eax, 85h
    61.         int 2Eh
    62.         pop edx
    63.  
    64. load_drv:   call    CreateFileA, offset aslashname, \
    65.             GENERIC_READ+GENERIC_WRITE, \
    66.             FILE_SHARE_READ+FILE_SHARE_WRITE, \
    67.             0, OPEN_EXISTING, 0, 0
    68.         test    eax, eax
    69.         js  err_drv
    70.         mov [drv_handle], eax
    71.  
    72. ...
    73. ...
    74. дальше обычная работа с драйвером, одинаковая и для NT, и для 9x.
    75. Перед завершением ессно надо сделать cleanup -- удалить
    76. добавленный в реестр crap и файл драйвера в \System.
    77. ...
    78. ...
    79.  
    80. (вспом. процедуры)
    81.  
    82. ;------------------------------------------------------------------
    83. ; win9x ring0 memory-allocation routines
    84. ;------------------------------------------------------------------
    85. .data?
    86. VxDCall_addr    dd  ?
    87.  
    88. .code
    89. Get_VxDCall:    pushstr 'kernel32.dll'
    90.         call    LoadLibraryA
    91.         mov ecx, [eax+3Ch]
    92.         mov edx, [ecx+eax+78h]
    93.         add edx, eax
    94.         mov edx, [edx+1Ch]  ; AddressOfFunctions RVA
    95.         add edx, eax
    96.         mov edi, [edx]
    97.         add eax, edi    ; eax = VxDCall linaddr
    98.         mov [VxDCall_addr], eax
    99.         ret
    100.  
    101. Ring0_malloc:   push    ebx
    102.         mov ebx, eax
    103.         push    8       ; PR_FIXED
    104.         push    eax
    105.         push    80080000h   ;60000h ; PR_SHARED
    106.         push    10000h      ; _PageReserve
    107.         call    [VxDCall_addr]
    108.         push    eax
    109.         push    60008h      ; PC_FIXED + PC_USER + PC_WRITEABLE
    110.         push    0
    111.         push    3       ; PD_FIXEDZERO
    112.         push    ebx     ; nPages
    113.         shr eax, 12
    114.         push    eax
    115.         push    10001h
    116.         call    [VxDCall_addr]
    117.         pop eax
    118.         pop ebx
    119.         ret
    120.  
    121. Ring0_free: push    0
    122.         push    eax
    123.         push    10002h
    124.         call    [VxDCall_addr]
    125.         ret
    Чтобы заставить этот int 2Eh/85h работать, пришлось слегка поковырять ntkern.vxd и разобрать как он их грузит (в основном, почему не грузит ;) ). В первую очередь напоролся на молчаливый отказ в загрузке, если драйвер находится не в \SYSTEM, затем поперли случайные падения при загрузке драйвера -- именно отсюда копирование regpath драйвера в System Area перед вызовом -- иначе бы работало через раз.

    Насчет ограничений -- n-ое кол-во перезапусков драйвера в принципе мешает только при интенсивной отладке, когда много раз грузишь-отлаживаешь-правишь баги-пересобираешь-по кругу. А так при обычной загрузке проблемы нет -- один раз грузится динамически, затем при повторном запуске проги проверяется, загружен ли уже драйвер, загружен -- значит используем без загрузки. То, что он остается до перезагрузки системы -- вообще фиолетово.

    В аттаче фрагмент ntkern.vxd, с именами экспортируемых функций -- может пригодиться, чтобы быстро глянуть, поддерживает ли он конкретную функцию или нет.
     
  4. lukash

    lukash New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2006
    Сообщения:
    142
    _BC_

    Спасибо!
    Теперь уже точно разберусь (в общем уже вроде разобрался, ща буду играться с этим всем:))

    Крута:) Просто интересно было как он работает, вот и поковырял его немножко (как раз аcpi изучал)