Reading ntdll.dll + offset results in an access violation

1.9k views Asked by At

I'm trying to read byte by byte the memory of ntdll.dll which is loaded inside my executable. The executable is compiled as a x32 executable on my x64 windows 7 machine.

I wrote a function called FindPattern which receives a specific byte array and it looks for this byte array in the ntdll.dll module.

I have checked this function on other modules and i'm sure it works fine.

now when im using this function on my ntdll module, it crashes when it reads memory ntdll + 0x1000.

i checked this on windbg, and windbg as well cant read the memory as well:

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

I have no clue why this exactly happen, but it consists for 0x9000 bytes

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$.............

it didnt happen in any other DLL i checked.. the problem can be bypassed using ReadProcessMemory but i want to understand what is causing it.

running the !dh command results:

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

why is this 10000 section alignment and 10000 base of code which both seem to include the right value i need to avoid the crashing and access violation.

what is causing it and why does it only happen in ntdll?

1

There are 1 answers

3
Ross Ridge On

There are gaps in the loaded image as shown in your dump. The file header gets loaded at 0x77df0000 then the .text section gets loaded 64k bytes after at 0x77e00000. This is a result of the 64k section alignment you noted in your post. I don't know if there's any reason for the unusual section alignment, except for the obvious reason they want some buffer or other element allocated with a 64k alignment. It might be somehow related to the fact that VirtualAlloc has 64k granularity.

You can use VirtualQuery to determine which pages are valid. Every time your "for loop" advances to a new page then call VirtualQuery. If the State value is MEM_COMMIT and the AllocationProtect value has one of the PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_READONLY or PAGE_READWRITE bits sets and AllocatonProtect value doesn't have the PAGE_GUARD bit set then you know that page exists and is readable. If not then you can use the RegionSize value to skip over that page, along with every page that follows it that has the same state.

You can also parse the PECOFF headers at 0x77df0000 to figure out where the sections are loaded, but that's a fair bit more complicated.