Чтение ntdll.dll + offset приводит к нарушению прав доступа

Я пытаюсь байт за байтом прочитать память ntdll.dll, которая загружена в мой исполняемый файл. Исполняемый файл скомпилирован как исполняемый файл x32 на моем компьютере с x64 Windows 7.

Я написал функцию FindPattern, которая получает определенный массив байтов и ищет этот массив байтов в модуле ntdll.dll.

Я проверил эту функцию на других модулях и уверен, что она работает нормально.

теперь, когда я использую эту функцию в моем модуле ntdll, он падает, когда читает память ntdll + 0x1000.

Я проверил это на Windbg, и Windbg также не может прочитать память:

0:000> db ntdll + FF0 L20
77df0ff0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
77df1000  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????

Я понятия не имею, почему именно это происходит, но он состоит из 0x9000 байт.

0:000> db ntdll + FFF0 L20
77dffff0  ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ??  ????????????????
77e00000  8b 44 24 04 cc c2 04 00-cc 90 c3 90 cc c3 90 90  .D$.............

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

результаты выполнения команды !dh:

0:000> !dh ntdll

File Type: DLL
FILE HEADER VALUES
     14C machine (i386)
       5 number of sections
55636317 time date stamp Mon May 25 20:59:51 2015

       0 file pointer to symbol table
       0 number of symbols
      E0 size of optional header
    2102 characteristics
            Executable
            32 bit word machine
            DLL

OPTIONAL HEADER VALUES
     10B magic #
    9.00 linker version
   D6400 size of code
   67400 size of initialized data
       0 size of uninitialized data
       0 address of entry point
   10000 base of code
         ----- new -----
77df0000 image base
   10000 section alignment
     200 file alignment
       3 subsystem (Windows CUI)
    6.01 operating system version
    6.01 image version
    6.01 subsystem version
  180000 size of image
     400 size of headers
  14C3B3 checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
     140  DLL characteristics
            Dynamic base
            NX compatible
   10218 [    F6D2] address [size] of Export Directory
       0 [       0] address [size] of Import Directory
  110000 [   5A028] address [size] of Resource Directory
       0 [       0] address [size] of Exception Directory
  13C600 [    3A18] address [size] of Security Directory
  170000 [    4D30] address [size] of Base Relocation Directory
   E60F4 [      38] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
   71C80 [      40] address [size] of Load Configuration Directory
       0 [       0] address [size] of Bound Import Directory
       0 [       0] address [size] of Import Address Table Directory
       0 [       0] address [size] of Delay Import Directory
       0 [       0] address [size] of COR20 Header Directory
       0 [       0] address [size] of Reserved Directory


SECTION HEADER #1
   .text name
   D6153 virtual size
   10000 virtual address
   D6200 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read


Debug Directories(2)
    Type       Size     Address  Pointer
    cv           23       e6130    d6530    Format: RSDS, guid, 2, wntdll.pdb
    (    10)       4       e612c    d652c

SECTION HEADER #2
      RT name
     1C9 virtual size
   F0000 virtual address
     200 size of raw data
   D6600 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

SECTION HEADER #3
   .data name
    82A8 virtual size
  100000 virtual address
    6E00 size of raw data
   D6800 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
C0000040 flags
         Initialized Data
         (no align specified)
         Read Write

SECTION HEADER #4
   .rsrc name
   5A028 virtual size
  110000 virtual address
   5A200 size of raw data
   DD600 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
40000040 flags
         Initialized Data
         (no align specified)
         Read Only

SECTION HEADER #5
  .reloc name
    4D30 virtual size
  170000 virtual address
    4E00 size of raw data
  137800 file pointer to raw data
       0 file pointer to relocation table
       0 file pointer to line numbers
       0 number of relocations
       0 number of line numbers
42000040 flags
         Initialized Data
         Discardable
         (no align specified)
         Read Only

почему это 10000 section alignment и 10000 base of code, которые, кажется, содержат правильное значение, которое мне нужно, чтобы избежать сбоя и нарушения прав доступа.

что вызывает это и почему это происходит только в ntdll?


person 0xAK    schedule 13.06.2015    source источник
comment
Я предполагаю, что Windows защищает ntdll.dll от людей, которые возятся с его внутренними компонентами из соображений безопасности.   -  person Remy Lebeau    schedule 13.06.2015
comment
Разрыв существует, потому что выравнивание раздела составляет 64 КиБ. !address ntdll + 1000 показывает, что этот адрес начинает зарезервированную (не зафиксированную) область размером 0xf000 байт. Что касается того, почему выравнивание раздела составляет 64 КБ, я знаю только, что оно должно быть кратно выравниванию файла (обычно 512 байт) и размеру страницы (4 КБ на x86), и что по умолчанию 4 КБ на x86 и x64. .   -  person Eryk Sun    schedule 14.06.2015
comment
@RemyLebeau, это звучит очень странно и необычно. какую защиту это даст? @eryksun, я не совсем понимаю ... есть ли другая dll, в которой это может произойти? похоже, что он зарезервировал 10 страниц (0x10 * sizeof(PAGE)), что звучит как случайное число, которое нужно сохранить.   -  person 0xAK    schedule 14.06.2015
comment
@ RE-Beginner Это не случайное число, это число, необходимое для загрузки раздела .text с выравниванием 64k. Почему разделы имеют выравнивание 64 КБ, является загадкой, но заполнение соответствует ожидаемому, учитывая, что они есть.   -  person Ross Ridge    schedule 14.06.2015
comment
Выравнивание файла составляет 512 байт, поэтому для заголовка файла должна быть зафиксирована только одна страница только для чтения (4096 байт). Обратите внимание, что все разделы (например, .text) начинаются с кратного выравнивания раздела. Однако это все одно распределение, поэтому любые незафиксированные страницы будут MEM_RESERVE. юзер32 такой же. Сравните это с kernel32, который использует 0x10000 как для выравнивания файла, так и для выравнивания раздела, поэтому заголовок только для чтения фиксирует 16 страниц, 15 из которых все 0. Затем есть advapi32, который использует выравнивание раздела по умолчанию, поэтому его раздел .text начинается в advapi32 + 0x1000.   -  person Eryk Sun    schedule 14.06.2015


Ответы (1)


В загруженном изображении есть пробелы, как показано в вашем дампе. Заголовок файла загружается по адресу 0x77df0000, затем раздел .text загружается через 64 ​​КБ по адресу 0x77e00000. Это результат выравнивания раздела 64 КБ, которое вы отметили в своем посте. Я не знаю, есть ли какая-либо причина для необычного выравнивания разделов, за исключением очевидной причины, по которой они хотят, чтобы какой-то буфер или другой элемент был выделен с выравниванием 64 КБ. Это может быть как-то связано с тем, что VirtualAlloc имеет гранулярность 64 КБ. .

Вы можете использовать VirtualQuery, чтобы определить, какие страницы допустимы. Каждый раз, когда ваш «цикл for» переходит на новую страницу, вызывайте VirtualQuery. Если значение State равно MEM_COMMIT, а значение AllocationProtect имеет один из наборов битов PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY или PAGE_READWRITE, а значение AllocatonProtect не имеет установленного бита PAGE_GUARD, то вы знаете, что страница существует и доступна для чтения. Если нет, то вы можете использовать значение RegionSize, чтобы пропустить эту страницу вместе с каждой следующей за ней страницей, имеющей такое же состояние.

Вы также можете проанализировать заголовки PECOFF по адресу 0x77df0000, чтобы выяснить, где загружаются секции, но это немного сложнее.

person Ross Ridge    schedule 13.06.2015
comment
Итак, как именно вы порекомендуете справиться с проблемой в реальном коде? Предполагая, что у меня есть For loop для всего адреса памяти модуля. и мне нужно прочитать каждый байт отдельно. - person 0xAK; 14.06.2015
comment
@RE-Beginner RE-Beginner Я обновил свой ответ объяснением того, как использовать VirtualQuery. - person Ross Ridge; 14.06.2015
comment
В качестве побочного примечания для тех, кто пытается использовать RE здесь, многие вещи в ntdll.dll явно противоречат спецификации pecoff. Это драконы. - person meawoppl; 02.08.2015