Драйверы режима ядра: Часть 8: Базовая техника: Работа с памятью. Совместно используемый раздел

Дата публикации 13 ноя 2003

Драйверы режима ядра: Часть 8: Базовая техника: Работа с памятью. Совместно используемый раздел — Архив WASM.RU



Прежде чем обратиться непосредственно к теме этой статьи, нам необходимо вкратце рассмотреть структурную обработку исключений (Structured Exception Handling, SEH), т.к. она нам потребуется.


8.1 Структурная обработка исключений

Я не буду подробно рассказывать о том, что это такое. Если дружите с английским языком, настоятельно советую найти и прочитать статью “Win32 Exception handling for assembler programmers” by Jeremy Gordon. Она написана применительно к режиму пользователя, но SEH – это универсальный механизм обработки исключений, как в режиме пользователя, так и в режиме ядра. Существует, однако, одно, но очень существенное отличие: в ядре с помощью SEH можно обработать не все исключения! Например, попытка деления на ноль приведет к краху системы даже при установленном обработчике SEH. Самое ужасное, что обращение к невыделенной памяти ядра также приводит к появлению BSOD. А обращение к невыделенной памяти режима пользователя легко обрабатывается SEH. Так что единственная возможность избежать краха – писать код так, чтобы он не вызывал необрабатываемых исключений.

8.1.1 Исходный текст драйвера seh

Код (Text):
  1.  
  2.  
  3.  ;@echo off
  4.  ;goto make
  5.  
  6.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  7.  ;
  8.  ;  SEH – Структурная обработка исключений.
  9.  ;
  10.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  11.  
  12.  .386
  13.  .model flat, stdcall
  14.  option casemap:none
  15.  
  16.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  17.  ;                              В К Л Ю Ч А Е М Ы Е    Ф А Й Л Ы
  18.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  19.  
  20.  include \masm32\include\w2k\ntstatus.inc
  21.  include \masm32\include\w2k\ntddk.inc
  22.  include \masm32\include\w2k\ntoskrnl.inc
  23.  
  24.  includelib \masm32\lib\w2k\ntoskrnl.lib
  25.  
  26.  include \masm32\Macros\Strings.mac
  27.  
  28.  include seh0.inc
  29.  
  30.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  31.  ;                                       С Т Р У К Т У Р Ы                                          
  32.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  33.  
  34.  SEH STRUCT
  35.      SafeEip         dd  ?   ; Точка, с которой будет продолжено выполнение потока
  36.      PrevEsp         dd  ?   ; Предыдущее значение esp
  37.      PrevEbp         dd  ?   ; Предыдущее значение ebp
  38.  SEH ENDS
  39.  
  40.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  41.  ;                    Н Е И Н И Ц И А Л И З И Р О В А Н Н Ы Е    Д А Н Н Ы Е
  42.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  43.  
  44.  .data?
  45.  
  46.  seh SEH <>
  47.  
  48.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  49.  ;                                           К О Д                                                  
  50.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  51.  
  52.  .code
  53.  
  54.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  55.  ;                                       BuggyReader                                                
  56.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  57.  
  58.  BuggyReader proc
  59.  
  60.      xor eax, eax
  61.      mov eax, [eax]              ; !!! Без SEH - BSOD !!!
  62.  
  63.      ret
  64.  
  65.  BuggyReader endp
  66.  
  67.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  68.  ;                                       BuggyWriter                                                
  69.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  70.  
  71.  BuggyWriter proc
  72.  
  73.      mov eax, MmUserProbeAddress
  74.      mov eax, [eax]
  75.      mov eax, [eax]
  76.    
  77.      mov byte ptr [eax], 0       ; !!! Без SEH - BSOD !!!
  78.  
  79.      ret
  80.  
  81.  BuggyWriter endp
  82.  
  83.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  84.  ;                                      ExceptionHandler                                            
  85.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  86.  
  87.  ExceptionHandler proc C uses esi pExcept:DWORD, pFrame:DWORD, pContext:DWORD, pDispatch:DWORD
  88.  
  89.      mov esi, pExcept
  90.  
  91.      invoke DbgPrint, $CTA0("\nSEH: An exception %08X has occured\n"), \
  92.                          [esi][EXCEPTION_RECORD.ExceptionCode]
  93.  
  94.      .if [esi][EXCEPTION_RECORD.ExceptionCode] == 0C0000005h
  95.  
  96.          ; Если произошло исключение типа EXCEPTION_ACCESS_VIOLATION,
  97.          ; то выводим дополнительную информацию.
  98.  
  99.          invoke DbgPrint, $CTA0("     Access violation at address: %08X\n"), \
  100.                          [esi][EXCEPTION_RECORD.ExceptionAddress]
  101.  
  102.          .if [esi][EXCEPTION_RECORD.ExceptionInformation][0]         ; Попытка чтения или записи ?
  103.  
  104.              invoke DbgPrint, $CTA0("     The code tried to write to address %08X\n\n"), \
  105.                          [esi][EXCEPTION_RECORD.ExceptionInformation][4]
  106.          .else
  107.              invoke DbgPrint, $CTA0("     The code tried to read from address %08X\n\n"), \
  108.                          [esi][EXCEPTION_RECORD.ExceptionInformation][4]
  109.          .endif
  110.      .endif
  111.  
  112.      lea eax, seh
  113.      push (SEH PTR [eax]).SafeEip
  114.      push (SEH PTR [eax]).PrevEsp
  115.      push (SEH PTR [eax]).PrevEbp
  116.  
  117.      mov eax, pContext
  118.      pop (CONTEXT PTR [eax]).regEbp
  119.      pop (CONTEXT PTR [eax]).regEsp
  120.      pop (CONTEXT PTR [eax]).regEip
  121.  
  122.      xor eax, eax
  123.      ret
  124.  
  125.  ExceptionHandler endp
  126.  
  127.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  128.  ;                                       DriverEntry                                                
  129.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  130.  
  131.  DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
  132.  
  133.      invoke DbgPrint, $CTA0("\nSEH: Entering DriverEntry\n")
  134.  
  135.      ;::::::::::::::::::::::::::::::::
  136.      ; Ставим SEH “вручную”
  137.      ;::::::::::::::::::::::::::::::::
  138.  
  139.      assume fs:nothing
  140.      push offset ExceptionHandler
  141.      push fs:[0]
  142.      mov fs:[0], esp
  143.      assume fs:error
  144.  
  145.      mov seh.SafeEip, offset SafePlace
  146.      mov seh.PrevEbp, ebp
  147.      mov seh.PrevEsp, esp
  148.  
  149.      invoke BuggyReader
  150.  
  151.  SafePlace:
  152.  
  153.      assume fs:nothing
  154.      pop fs:[0]
  155.      add esp, sizeof DWORD
  156.      assume fs:error
  157.  
  158.      ;:::::::::::::::::::::::::::::::::::::::::::::::
  159.      ; Используем макросы. Это чуть-чуть проще <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3    :smile3:">
  160.      ;:::::::::::::::::::::::::::::::::::::::::::::::
  161.  
  162.      _try
  163.  
  164.      invoke BuggyWriter
  165.  
  166.      _finally
  167.  
  168.  
  169.      invoke DbgPrint, $CTA0("\nSEH: Leaving DriverEntry\n")
  170.  
  171.      mov eax, STATUS_DEVICE_CONFIGURATION_ERROR
  172.      ret
  173.  
  174.  DriverEntry endp
  175.  
  176.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  177.  ;                                                                                                    
  178.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  179.  
  180.  end DriverEntry
  181.  
  182.  :make
  183.  
  184.  set drv=seh
  185.  
  186.  \masm32\bin\ml /nologo /c /coff %drv%.bat
  187.  \masm32\bin\link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native %drv%.obj
  188.  
  189.  del %drv%.obj
  190.  
  191.  echo.
  192.  pause
  193.  
  194.  


8.1.2 Устанавливаем SEH-фрейм

Код (Text):
  1.  
  2.  
  3.      assume fs:nothing
  4.  
  5.  

По умолчанию masm запрещает использование регистра fs. Снимаем это ограничение с помощью директивы assume.

Код (Text):
  1.  
  2.  
  3.      push offset ExceptionHandler
  4.      push fs:[0]
  5.      mov fs:[0], esp
  6.  
  7.  

Устанавливаем так называемый SEH-фрейм, который определяет адрес обработчика исключений. Начиная с этого момента обрабатываемые исключения, происходящие в потоке (каждый поток имеет свои собственные обработчики, если конечно они установлены) будут приводить к вызову системой этого обработчика. В данном случае - это процедура ExceptionHandler, код которой мы рассмотрим позже. Для получения информации обо всех обработчиках установленных в текущем потоке отладчик SoftICE предоставляет команду xframe.

Код (Text):
  1.  
  2.  
  3.      assume fs:error
  4.  
  5.  

Запрещаем дальнейшее использование регистра fs, как было установлено по умолчанию.

Код (Text):
  1.  
  2.  
  3.      mov seh.SafeEip, offset SafePlace
  4.      mov seh.PrevEbp, ebp
  5.      mov seh.PrevEsp, esp
  6.  
  7.  

Для того чтобы после обработки исключения наш обработчик смог возобновить выполнение потока мы должны сохранить значения регистров esp, ebp и указать на точку, с которой поток продолжит выполнение. Сохраняем эти три значения в структуре seh и вызываем процедуру BuggyReader, которая попытается прочитать двойное слово по адресу 00000000.

Код (Text):
  1.  
  2.  
  3.  BuggyReader proc
  4.  
  5.      xor eax, eax
  6.      mov eax, [eax]
  7.  
  8.      ret
  9.  
  10.  BuggyReader endp
  11.  
  12.  

Обращение по нулевому указателю являлось столь частой ошибкой, что Microsoft пришлось отвести 64 килобайта памяти в диапазоне 00000000-0000FFFFh и сделать этот регион недоступным. Обращение к любому байту в этом диапазоне приводит к исключению типа EXCEPTION_ACCESS_VIOLATION.


8.1.3 Обрабатываем исключение

При попытке чтения с адреса 00000000 в процедуре BuggyReader происходит исключение, и мы попадаем в установленный нами обработчик.

Код (Text):
  1.  
  2.  
  3.      mov esi, pExcept
  4.  
  5.      invoke DbgPrint, $CTA0("\nSEH: An exception %08X has occured\n"), \
  6.                          [esi][EXCEPTION_RECORD.ExceptionCode]
  7.  
  8.      .if [esi][EXCEPTION_RECORD.ExceptionCode] == 0C0000005h
  9.  
  10.          invoke DbgPrint, $CTA0("     Access violation at address: %08X\n"), \
  11.                          [esi][EXCEPTION_RECORD.ExceptionAddress]
  12.  
  13.          .if [esi][EXCEPTION_RECORD.ExceptionInformation][0]         ; Попытка чтения или записи ?
  14.  
  15.              invoke DbgPrint, $CTA0("     The code tried to write to address %08X\n\n"), \
  16.                          [esi][EXCEPTION_RECORD.ExceptionInformation][4]
  17.          .else
  18.              invoke DbgPrint, $CTA0("     The code tried to read from address %08X\n\n"), \
  19.                          [esi][EXCEPTION_RECORD.ExceptionInformation][4]
  20.          .endif
  21.      .endif
  22.  
  23.  

Первым делом наш обработчик выводит соответствующее отладочное сообщение и, если произошло исключение типа EXCEPTION_ACCESS_VIOLATION, кое-какую дополнительную информацию. Затем приступаем к собственно обработке исключения.

Код (Text):
  1.  
  2.  
  3.      lea eax, seh
  4.      push (SEH PTR [eax]).SafeEip
  5.      push (SEH PTR [eax]).PrevEsp
  6.      push (SEH PTR [eax]).PrevEbp
  7.  
  8.      mov eax, pContext
  9.      pop (CONTEXT PTR [eax]).regEbp
  10.      pop (CONTEXT PTR [eax]).regEsp
  11.      pop (CONTEXT PTR [eax]).regEip
  12.  
  13.  

У нас обработка исключения заключается в простом восстановлении значений в регистрах esp, ebp и помещении в регистр eip адреса, с которого безопасно продолжить выполнение потока. Эти данные обработчик извлекает из предварительно заполненной нами структуры seh и помещает их в структуру CONTEXT, указатель на которую передается системой.

Код (Text):
  1.  
  2.  
  3.      xor eax, eax
  4.      ret
  5.  
  6.  

Возвращаем значение ExceptionContinueExecution равное нулю, которое сообщает системе, что она должна перезагрузить контекст потока и продолжить его выполнение. Т.к. значение eip равно адресу метки SafePlace, а значения в регистрах esp и ebp восстановлены, то поток продолжит своё выполнение с метки SafePlace, как ни в чем не бывало.


8.1.4 Удаляем SEH-фрейм

Код (Text):
  1.  
  2.  
  3.  SafePlace:
  4.  
  5.      assume fs:nothing
  6.      pop fs:[0]
  7.      add esp, sizeof DWORD
  8.      assume fs:error
  9.  
  10.  

Восстанавливаем старое значение в fs:[0] и корректируем указатель стека (подробности см. в вышеупомянутой статье).


8.1.5 Используем макросы для установки/удаления SEH-фрейма

Проделаем ту же самую операцию с помощью макросов, которые я написал для упрощения работы с SEH. Макросы определены в файле seh0.inc. Описывать их я не буду, т.к. делают они то же самое, что мы только что разобрали. Если в обработчике исключений не требуется какой-то особой обработки, то при использовании макросов _try/_finally весь вышеприведенный код сведется к трем строчкам. Точкой SafePlace, в данном случае, будет строка, в которой стоит макрос _finally.

Код (Text):
  1.  
  2.  
  3.      _try
  4.  
  5.      invoke BuggyWriter
  6.  
  7.      _finally
  8.  
  9.  

На этот раз вызовем процедуру BuggyWriter, которая попытается записать двойное слово по адресу MmUserProbeAddress (7FFF0000h).

Код (Text):
  1.  
  2.  
  3.  BuggyWriter proc
  4.  
  5.  
  6.      mov eax, MmUserProbeAddress
  7.      mov eax, [eax]
  8.      mov eax, [eax]
  9.    
  10.      mov byte ptr [eax], 0
  11.      ret
  12.  
  13.  BuggyWriter endp
  14.  
  15.  

64Кб памяти в диапазоне 7FFF0000h – 7FFFFFFFh являются недоступным регионом, зарезервированным для предотвращения передачи буферов через границу пользовательского и системного пространства. Стартовый адрес этого региона содержится в экспортируемой ядром переменной MmUserProbeAddress.

Вооружившись знаниями о структурной обработке исключений, переходим к следующему примеру, где нам потребуется из драйвера обратиться к памяти режима пользователя. Подобные обращения крайне желательно заключать в SEH-фрейм.


8.2 Разделяемый объект “раздел”

Windows предоставляет богатейший набор механизмов для обмена данными между двумя и более процессами (Interprocess Communications, IPC): буфер обмена, DDE, оконные сообщения (в частности WM_COPYDATA), почтовые ящики (mailslot), сокеты (sockets) и др. Все эти механизмы, так или иначе, базируются на объекте “проекция файла” (file-mapping object), представляющем собой блок памяти доступный двум и более процессам для совместного использования. В терминологии DDK проецируемые файлы являются объектами “раздел” (section object), в просторечии называемыми секциями (не путать с секциями PE-файла).

Объект “раздел” является самым низкоуровневым механизмом совместного использования данных. Этот же самый объект используется системой для загрузки исполняемых образов в память, а диспетчер кэша использует его для доступа к данным в кэшированных файлах. Объект “раздел” также позволяет проецировать файлы на диске в адресные пространства процессов и работать с ними не как с файлами, а как с блоками памяти.

Совместное использование данных с помощью объекта “раздел” происходит следующим образом: один процесс создает отображаемый в память файл, вызывая функцию CreateFileMapping. Затем, вызовом функции MapViewOfFile (если спуститься на один уровень глубже, то вызывается NtMapViewOfSection), отображает его представление (view) на свое адресное пространство, а другой процесс через OpenFileMapping открывает тот же самый отображаемый файл и так же отображает его, но уже в свое адресное пространство. В результате одни и те же физические страницы памяти становятся доступными в обоих процессах, что позволяет им легко передавать через эту область большие порции данных, т.к. любые изменения на этих страницах в одном процессе отражаются на представление в другом процессе.

Совместно используемый объект “раздел” может служить средством обмена данными не только для пользовательских процессов, но и для драйверов. Или, как в следующем примере, именованный объект “раздел” будет использован для обмена данными между пользовательским процессом и драйвером.


8.2.1 Исходный текст программы управления драйвером SharedSection

Код (Text):
  1.  
  2.  
  3.  ;@echo off
  4.  ;goto make
  5.  
  6.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  7.  ;
  8.  ;  SharedSection – Клиент драйвера SharedSection.sys
  9.  ;
  10.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  11.  
  12.  .386
  13.  .model flat, stdcall
  14.  option casemap:none
  15.  
  16.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  17.  ;                              В К Л Ю Ч А Е М Ы Е    Ф А Й Л Ы
  18.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  19.  
  20.  include \masm32\include\windows.inc
  21.  
  22.  include \masm32\include\w2k\native.inc
  23.  include \masm32\include\w2k\ntstatus.inc
  24.  include \masm32\include\winioctl.inc
  25.  
  26.  include \masm32\include\kernel32.inc
  27.  include \masm32\include\user32.inc
  28.  include \masm32\include\advapi32.inc
  29.  include \masm32\include\w2k\ntdll.inc
  30.  
  31.  includelib \masm32\lib\kernel32.lib
  32.  includelib \masm32\lib\user32.lib
  33.  includelib \masm32\lib\advapi32.lib
  34.  includelib \masm32\lib\w2k\ntdll.lib
  35.  
  36.  include \masm32\Macros\Strings.mac
  37.  
  38.  include ..\common.inc
  39.  
  40.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  41.  ;                                           К О Д                                                  
  42.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  43.  
  44.  .code
  45.  
  46.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  47.  ;                                    CallDriver                                                    
  48.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  49.  
  50.  CallDriver proc
  51.  
  52.  local fOk:BOOL
  53.  
  54.  local hSCManager:HANDLE
  55.  local hService:HANDLE
  56.  local acModulePath[MAX_PATH]:CHAR
  57.  local _ss:SERVICE_STATUS
  58.  local hDevice:HANDLE
  59.  
  60.  local abyOutBuffer[4]:BYTE
  61.  local dwBytesReturned:DWORD
  62.  
  63.      and fOk, FALSE
  64.  
  65.      invoke OpenSCManager, NULL, NULL, SC_MANAGER_ALL_ACCESS
  66.      .if eax != NULL
  67.          mov hSCManager, eax
  68.  
  69.          push eax
  70.          invoke GetFullPathName, $CTA0("SharedSection.sys"), sizeof acModulePath, addr acModulePath, esp
  71.          pop eax
  72.  
  73.          invoke CreateService, hSCManager, $CTA0("SharedSection"), $CTA0("One way to share section"), \
  74.              SERVICE_START + SERVICE_STOP + DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, \
  75.              SERVICE_ERROR_IGNORE, addr acModulePath, NULL, NULL, NULL, NULL, NULL
  76.  
  77.          .if eax != NULL
  78.              mov hService, eax
  79.  
  80.              invoke StartService, hService, 0, NULL
  81.              .if eax != 0
  82.  
  83.                  invoke CreateFile, $CTA0("\\\\.\\SharedSection"), 0, \
  84.                                          0, NULL, OPEN_EXISTING, 0, NULL
  85.  
  86.                  .if eax != INVALID_HANDLE_VALUE
  87.                      mov hDevice, eax
  88.  
  89.                      ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  90.  
  91.                      invoke DeviceIoControl, hDevice, IOCTL_SHARE_MY_SECTION, NULL, 0, NULL, 0, \
  92.                                                  addr dwBytesReturned, NULL
  93.                      .if eax != 0
  94.                          inc fOk
  95.                      .else
  96.                          invoke MessageBox, NULL, $CTA0("Can't send control code to device."), NULL, \
  97.                                                      MB_OK + MB_ICONSTOP
  98.                      .endif
  99.  
  100.                      ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  101.  
  102.                      invoke CloseHandle, hDevice
  103.                  .else
  104.                      invoke MessageBox, NULL, $CTA0("Device is not present."), NULL, MB_ICONSTOP
  105.                  .endif
  106.                  invoke ControlService, hService, SERVICE_CONTROL_STOP, addr _ss
  107.              .else
  108.                  invoke MessageBox, NULL, $CTA0("Can't start driver."), NULL, MB_OK + MB_ICONSTOP
  109.              .endif
  110.              invoke DeleteService, hService
  111.              invoke CloseServiceHandle, hService
  112.          .else
  113.              invoke MessageBox, NULL, $CTA0("Can't register driver."), NULL, MB_OK + MB_ICONSTOP
  114.          .endif
  115.          invoke CloseServiceHandle, hSCManager
  116.      .else
  117.          invoke MessageBox, NULL, $CTA0("Can't connect to Service Control Manager."), \
  118.                                  NULL, MB_OK + MB_ICONSTOP
  119.      .endif
  120.  
  121.      mov eax, fOk
  122.      ret
  123.  
  124.  CallDriver endp
  125.  
  126.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  127.  ;                                         start                                                    
  128.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  129.  
  130.  start proc
  131.  
  132.  local hSection:HANDLE
  133.  local liSectionSize:_LARGE_INTEGER
  134.  local oa:OBJECT_ATTRIBUTES
  135.  local pSectionBaseAddress:PVOID
  136.  local liViewSize:_LARGE_INTEGER
  137.  
  138.      and liSectionSize.HighPart, 0
  139.      mov liSectionSize.LowPart, SECTION_SIZE
  140.  
  141.      lea ecx, oa
  142.      InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
  143.  
  144.      invoke ZwCreateSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa, \
  145.                              addr liSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL
  146.      .if eax == STATUS_SUCCESS
  147.  
  148.          and pSectionBaseAddress, NULL
  149.          and liViewSize.HighPart, 0
  150.          and liViewSize.LowPart, 0
  151.          invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, \
  152.                            SECTION_SIZE, NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
  153.          .if eax == STATUS_SUCCESS
  154.  
  155.              CTA ".revird ecived a dna sessecorp resu neewteb yromem ", g_szStrToReverse
  156.              CTA "erahs ot euqinhcet emas eht esu nac uoy ,revewoH "
  157.              CTA ".sessecorp resu gnoma yromem gnirahs rof desu euqinhcet "
  158.              CTA0 "nommoc a si elif gnigap eht yb dekcab elif deppam-yromem A"
  159.  
  160.              invoke strcpy, pSectionBaseAddress, addr g_szStrToReverse
  161.  
  162.              invoke CallDriver
  163.              .if eax == TRUE
  164.                  invoke MessageBox, NULL, pSectionBaseAddress, \
  165.                                  $CTA0("HOWTO: Share Memory Between User Mode and Kernel Mode"), \
  166.                                  MB_OK + MB_ICONINFORMATION
  167.              .endif
  168.  
  169.              invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
  170.          .else
  171.              invoke MessageBox, NULL, $CTA0("Can't map section."), NULL, MB_OK + MB_ICONSTOP
  172.          .endif
  173.  
  174.          invoke ZwClose, hSection
  175.      .else
  176.          invoke MessageBox, NULL, $CTA0("Can't create section."), NULL, MB_OK + MB_ICONSTOP
  177.      .endif
  178.  
  179.      invoke ExitProcess, 0
  180.      ret
  181.  
  182.  start endp
  183.  
  184.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  185.  ;                                                                                                  
  186.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  187.  
  188.  end start
  189.  
  190.  :make
  191.  
  192.  set exe=SharedSection
  193.  
  194.  if exist ..\%exe%.exe del ..\%exe%.exe
  195.  
  196.  \masm32\bin\ml /nologo /c /coff %exe%.bat
  197.  \masm32\bin\link /nologo /subsystem:windows %exe%.obj
  198.  
  199.  del %exe%.obj
  200.  move %exe%.exe ..
  201.  if exist %exe%.exe del %exe%.exe
  202.  
  203.  echo.
  204.  pause
  205.  
  206.  

Разберем только ключевые моменты, все остальное должно быть понятно без комментариев.

Код (Text):
  1.  
  2.  
  3.      and liSectionSize.HighPart, 0
  4.      mov liSectionSize.LowPart, SECTION_SIZE
  5.  
  6.  

При создании раздела придется указать его размер. Т.к. этот размер может превышать 4Гб, то для задания размера используется переменная типа LARGE_INTEGER, которую мы инициализируем значением SECTION_SIZE равным размеру одной страницы (4Кб). Константа SECTION_SIZE определена в файле common.inc.

Код (Text):
  1.  
  2.  
  3.      lea ecx, oa
  4.      InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
  5.  
  6.  

С макросом InitializeObjectAttributes мы уже знакомы – как-то раз мы его уже использовали. Поскольку для последующего вызова ZwCreateSection требуется заполненная соответствующим образом структура OBJECT_ATTRIBUTES, то мы это и делаем, пользуясь этим макросом.

Раздел, который мы собираемся совместно использовать должен быть именованным, для того чтобы его можно было открыть по имени. Имя раздела определено в файле common.inc таким образом:

Код (Text):
  1.  
  2.  
  3.  .const
  4.  CCOUNTED_UNICODE_STRING    "\\BaseNamedObjects\\UserKernelSharedSection", g_usSectionName, 4
  5.  
  6.  

Объект ”раздел” попадет в каталог BaseNamedObjects пространства имен диспетчера объектов, в который обычно помещаются именованные объекты создаваемые пользовательскими процессами.

Код (Text):
  1.  
  2.  
  3.      invoke ZwCreateSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa, \
  4.                              addr liSectionSize, PAGE_READWRITE, SEC_COMMIT, NULL
  5.  
  6.  

Вызовом функции ZwCreateSection, создаем именованный объект “раздел” размером SECTION_SIZE доступный для чтения и записи. Если раздел будет создан, то в переменной hSection получим его описатель.

Код (Text):
  1.  
  2.  
  3.          and pSectionBaseAddress, NULL
  4.          and liViewSize.HighPart, 0
  5.          and liViewSize.LowPart, 0
  6.          invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, \
  7.                                      NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
  8.  
  9.  

Отображаем представление всего раздела в память. Здесь довольно много параметров – все они подробно описаны в DDK. Т.к. переменная pSectionBaseAddress инициализирована нулевым значением, система сама определит по какому виртуальному адресу ей удобнее отобразить раздел и вернет этот адрес в этой же переменной. Инициализированная нулем переменная liViewSize определяет, что раздел будет отображен полностью.

Код (Text):
  1.  
  2.  
  3.              CTA ".revird ecived a dna sessecorp resu neewteb yromem ", g_szStrToReverse
  4.              CTA "erahs ot euqinhcet emas eht esu nac uoy ,revewoH "
  5.              CTA ".sessecorp resu gnoma yromem gnirahs rof desu euqinhcet "
  6.              CTA0 "nommoc a si elif gnigap eht yb dekcab elif deppam-yromem A"
  7.  
  8.              invoke strcpy, pSectionBaseAddress, addr g_szStrToReverse
  9.  
  10.  

Копируем в полученное представление перевернутую строку. Задачей драйвера будет привести эту строку к читабельному виду.

Код (Text):
  1.  
  2.  
  3.              invoke CallDriver
  4.              .if eax == TRUE
  5.                  invoke MessageBox, NULL, pSectionBaseAddress, \
  6.                                  $CTA0("HOWTO: Share Memory Between User Mode and Kernel Mode"), \
  7.                                  MB_OK + MB_ICONINFORMATION
  8.              .endif
  9.  
  10.  

Значение TRUE возвращенное процедурой CallDriver означает, что драйвер справился со своей задачей. Показываем результаты его работы. В процедуре CallDriver мы проводим обычные операции регистрации и запуска драйвера и посылаем ему управляющий код IOCTL_SHARE_MY_SECTION.

Код (Text):
  1.  
  2.  
  3.              invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
  4.          .endif
  5.          invoke ZwClose, hSection
  6.  
  7.  

Приводим систему в исходное состояние.


8.2.2 Исходный текст драйвера SharedSection

Код (Text):
  1.  
  2.  
  3.  ;@echo off
  4.  ;goto make
  5.  
  6.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  7.  ;
  8.  ;  SharedSection – использует объект “раздел”, созданный программой управления.
  9.  ;
  10.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  11.  
  12.  .386
  13.  .model flat, stdcall
  14.  option casemap:none
  15.  
  16.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  17.  ;                              В К Л Ю Ч А Е М Ы Е    Ф А Й Л Ы                                    
  18.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  19.  
  20.  include \masm32\include\w2k\ntstatus.inc
  21.  include \masm32\include\w2k\ntddk.inc
  22.  include \masm32\include\w2k\ntoskrnl.inc
  23.  include \masm32\include\w2k\native.inc
  24.  
  25.  includelib \masm32\lib\w2k\ntoskrnl.lib
  26.  
  27.  include \masm32\Macros\Strings.mac
  28.  
  29.  include ..\common.inc
  30.  include seh0.inc
  31.  
  32.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  33.  ;                             Н Е И З М Е Н Я Е М Ы Е    Д А Н Н Ы Е                                
  34.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  35.  
  36.  .const
  37.  
  38.  CCOUNTED_UNICODE_STRING "\\Device\\SharedSection", g_usDeviceName, 4
  39.  CCOUNTED_UNICODE_STRING "\\DosDevices\\SharedSection", g_usSymbolicLinkName, 4
  40.  
  41.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  42.  ;                                              К О Д                                                
  43.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  44.  
  45.  .code
  46.  
  47.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  48.  ;                                   DispatchCreateClose                                            
  49.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  50.  
  51.  DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
  52.  
  53.      mov eax, pIrp
  54.      mov (_IRP PTR [eax]).IoStatus.Status, STATUS_SUCCESS
  55.      and (_IRP PTR [eax]).IoStatus.Information, 0
  56.  
  57.      fastcall IofCompleteRequest, pIrp, IO_NO_INCREMENT
  58.  
  59.      mov eax, STATUS_SUCCESS
  60.      ret
  61.  
  62.  DispatchCreateClose endp
  63.  
  64.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  65.  ;                                     DispatchControl                                              
  66.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  67.  
  68.  DispatchControl proc uses esi edi pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
  69.  
  70.  local hSection:HANDLE
  71.  local oa:OBJECT_ATTRIBUTES
  72.  local pSectionBaseAddress:PVOID
  73.  local liViewSize:LARGE_INTEGER
  74.  
  75.      invoke DbgPrint, $CTA0("\nSharedSection: Entering DispatchControl\n")
  76.  
  77.      mov esi, pIrp
  78.      assume esi:ptr _IRP
  79.  
  80.      mov [esi].IoStatus.Status, STATUS_UNSUCCESSFUL
  81.      and [esi].IoStatus.Information, 0
  82.  
  83.      IoGetCurrentIrpStackLocation esi
  84.      mov edi, eax
  85.      assume edi:ptr IO_STACK_LOCATION
  86.  
  87.      .if [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_SHARE_MY_SECTION
  88.  
  89.          invoke DbgPrint, $CTA0("SharedSection: Opening section object\n")
  90.  
  91.          lea ecx, oa
  92.          InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
  93.          invoke ZwOpenSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa
  94.          .if eax == STATUS_SUCCESS
  95.  
  96.              invoke DbgPrint, $CTA0("SharedSection: Section object opened\n")
  97.  
  98.              and pSectionBaseAddress, NULL
  99.              and liViewSize.HighPart, 0
  100.              and liViewSize.LowPart, 0
  101.              invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, \
  102.                           SECTION_SIZE, NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
  103.              .if eax == STATUS_SUCCESS
  104.  
  105.                  invoke DbgPrint, \
  106.                     $CTA0("SharedSection: Section mapped at address %08X\n"), pSectionBaseAddress
  107.  
  108.                  _try
  109.  
  110.                  invoke _strrev, pSectionBaseAddress
  111.                  mov [esi].IoStatus.Status, STATUS_SUCCESS
  112.  
  113.                  invoke DbgPrint, $CTA0("SharedSection: String reversed\n")
  114.  
  115.                  _finally
  116.  
  117.                  invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
  118.  
  119.                  invoke DbgPrint, $CTA0("SharedSection: Section at address %08X unmapped \n"), \
  120.                                             pSectionBaseAddress
  121.  
  122.              .else
  123.                  invoke DbgPrint, \
  124.                         $CTA0("SharedSection: Couldn't map view of section. Status: %08X\n"), eax
  125.              .endif
  126.              invoke ZwClose, hSection
  127.              invoke DbgPrint, $CTA0("SharedSection: Section object handle closed\n")
  128.          .else
  129.              invoke DbgPrint, $CTA0("SharedSection: Couldn't open section. Status: %08X\n"), eax
  130.          .endif
  131.  
  132.      .else
  133.          mov [esi].IoStatus.Status, STATUS_INVALID_DEVICE_REQUEST
  134.      .endif
  135.  
  136.      push [esi].IoStatus.Status
  137.  
  138.      assume edi:nothing
  139.      assume esi:nothing
  140.  
  141.      fastcall IofCompleteRequest, esi, IO_NO_INCREMENT
  142.  
  143.      invoke DbgPrint, $CTA0("SharedSection: Leaving DispatchControl\n")
  144.  
  145.      pop eax
  146.      ret
  147.  
  148.  DispatchControl endp
  149.  
  150.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  151.  ;                                       DriverUnload                                                
  152.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  153.  
  154.  DriverUnload proc pDriverObject:PDRIVER_OBJECT
  155.  
  156.      invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
  157.  
  158.      mov eax, pDriverObject
  159.      invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
  160.  
  161.      ret
  162.  
  163.  DriverUnload endp
  164.  
  165.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  166.  ;               В Ы Г Р У Ж А Е М Ы Й   П Р И   Н Е О Б Х О Д И М О С Т И   К О Д                  
  167.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  168.  
  169.  .code INIT
  170.  
  171.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  172.  ;                                       DriverEntry                                                
  173.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  174.  
  175.  DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
  176.  
  177.  local status:NTSTATUS
  178.  local pDeviceObject:PDEVICE_OBJECT
  179.  
  180.      mov status, STATUS_DEVICE_CONFIGURATION_ERROR
  181.  
  182.      invoke IoCreateDevice, pDriverObject, 0, addr g_usDeviceName, FILE_DEVICE_UNKNOWN, \
  183.                                       0, TRUE, addr pDeviceObject
  184.      .if eax == STATUS_SUCCESS
  185.          invoke IoCreateSymbolicLink, addr g_usSymbolicLinkName, addr g_usDeviceName
  186.          .if eax == STATUS_SUCCESS
  187.              mov eax, pDriverObject
  188.              assume eax:ptr DRIVER_OBJECT
  189.              mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)],          offset DispatchCreateClose
  190.              mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],           offset DispatchCreateClose
  191.              mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)],  offset DispatchControl
  192.              mov [eax].DriverUnload,                                         offset DriverUnload
  193.              assume eax:nothing
  194.              mov status, STATUS_SUCCESS
  195.          .else
  196.              invoke IoDeleteDevice, pDeviceObject
  197.          .endif
  198.      .endif
  199.  
  200.      mov eax, status
  201.      ret
  202.  
  203.  DriverEntry endp
  204.  
  205.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  206.  ;                                                                                                  
  207.  ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  208.  
  209.  end DriverEntry
  210.  
  211.  :make
  212.  
  213.  set drv=SharedSection
  214.  
  215.  \masm32\bin\ml /nologo /c /coff %drv%.bat
  216.  \masm32\bin\link /nologo /driver /base:0x10000 /align:32 /out:%drv%.sys /subsystem:native /ignore:4078 %drv%.obj
  217.  
  218.  del %drv%.obj
  219.  move %drv%.sys ..
  220.  
  221.  echo.
  222.  pause
  223.  
  224.  

При работе с разделяемыми ресурсами, в общем случае, требуется позаботиться о синхронизации, чтобы пишущий и читающий потоки не могли иметь одновременного доступа к разделяемому ресурсу. В данном же случае поток всего один и синхронизации не требуется.

Код (Text):
  1.  
  2.  
  3.          lea ecx, oa
  4.          InitializeObjectAttributes ecx, offset g_usSectionName, OBJ_CASE_INSENSITIVE, NULL, NULL
  5.          invoke ZwOpenSection, addr hSection, SECTION_MAP_WRITE + SECTION_MAP_READ, addr oa
  6.  
  7.  

Получив управляющий код IOCTL_SHARE_MY_SECTION, драйвер пытается открыть объект раздел с именем определенным в переменной g_usSectionName (см. common.inc).

Код (Text):
  1.  
  2.  
  3.          .if eax == STATUS_SUCCESS
  4.              and pSectionBaseAddress, NULL
  5.              and liViewSize.HighPart, 0
  6.              and liViewSize.LowPart, 0
  7.              invoke ZwMapViewOfSection, hSection, NtCurrentProcess, addr pSectionBaseAddress, 0, SECTION_SIZE, \
  8.                                     NULL, addr liViewSize, ViewShare, 0, PAGE_READWRITE
  9.              .if eax == STATUS_SUCCESS
  10.  
  11.  

Если описатель раздела получен, проецируем его представление. Вряд ли Вы найдете здесь какие-либо отличия от аналогичной части в программе управления. Но…

После вызова ZwMapViewOfSection переменная pSectionBaseAddress будет содержать значение из диапазона пользовательских адресов, а не адрес в области ядра, как Вы, возможно, ожидали. Это принципиальный момент, т.к. обращаться по этому адресу можно будет только в контексте того процесса, в адресное пространство которого отображен раздел. Поскольку драйвер SharedSection одноуровневый (а Вы помните, что обработка IRP типа IRP_MJ_DEVICE_CONTROL проходит в таком драйвере в контексте потока инициировавшего эту операцию), то мы находимся в контексте нашей программы управления.

Виртуальный адрес представления также будет отличаться от адреса представления сделанного в программе управления, но физические страницы, на которые отображён раздел будут совпадать. В нашем случае страница одна и на ней "лежит" перевернутая строка.

Код (Text):
  1.  
  2.  
  3.                  _try
  4.  
  5.                  invoke _strrev, pSectionBaseAddress
  6.                  mov [esi].IoStatus.Status, STATUS_SUCCESS
  7.  
  8.                  _finally
  9.  
  10.  

Установив SEH-фрейм, вызываем функцию _strrev, которая переворачивает строку. Теперь её можно будет легко прочитать.

Код (Text):
  1.  
  2.  
  3.                  invoke ZwUnmapViewOfSection, NtCurrentProcess, pSectionBaseAddress
  4.              .endif
  5.              invoke ZwClose, hSection
  6.          .endif
  7.  
  8.  

Освобождаем занятые ресурсы. В программе управления функция DeviceIoControl вернет код успеха и на экране отобразится восстановленная строка.

Рис. 8-1. Результат работы программы SharedSection.exe

Исходный код драйверов в архиве.

© Four-F

0 1.237
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532