读取 ntdll.dll + offset 会导致访问冲突
Posted
技术标签:
【中文标题】读取 ntdll.dll + offset 会导致访问冲突【英文标题】:Reading ntdll.dll + offset results in an access violation 【发布时间】:2015-08-29 14:45:00 【问题描述】:我正在尝试逐字节读取在我的可执行文件中加载的ntdll.dll
的内存。
该可执行文件在我的 x64 windows 7 机器上编译为 x32 可执行文件。
我编写了一个名为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中?
【问题讨论】:
我的猜测是,出于安全原因,Windows 正在保护ntdll.dll
免受人们对其内部的干扰。
存在间隙是因为节对齐为 64 KiB。 !address ntdll + 1000
显示此地址开始一个保留(未提交)区域,该区域为 0xf000 字节。至于为什么节对齐是 64 KiB,我只知道它必须是文件对齐(通常为 512 字节)和页面大小(x86 上为 4 KiB)的倍数,并且默认为 x86 和 x64 上的 4 KiB .
@RemyLebeau,这听起来很奇怪而且很离谱。这将提供什么样的保护? @eryksun,我不太明白……还有其他可能发生这种情况的dll吗?看起来它保留了 10 个页面 (0x10 * sizeof(PAGE)
),这听起来像是要保留的随机数..
@RE-Beginner 这不是一个随机数,它是加载具有 64k 对齐的 .text 部分所必需的数字。为什么这些部分有 64k 对齐是一个谜,但填充符合预期,因为它们确实如此。
文件对齐为 512 字节,因此只需为文件头提交一个只读页面(4096 字节)。请注意,所有部分(例如 .text)都以部分对齐的倍数开始。不过,这都是一次分配,所以任何未提交的页面都是MEM_RESERVE
。 user32 是一样的。比较一下 kernel32,它使用 0x10000 进行文件和节对齐,所以只读头提交 16 页,其中 15 个都是 0。然后是 advapi32,它使用默认的节对齐,所以它的 .text 节开始advapi32 + 0x1000
.
【参考方案1】:
如您的转储中所示,加载的图像中存在间隙。文件头在 0x77df0000 处加载,然后 .text 部分在 0x77e00000 处加载 64k 字节。这是您在帖子中提到的 64k 部分对齐的结果。我不知道不寻常的部分对齐是否有任何原因,除了他们想要一些缓冲区或其他元素分配有 64k 对齐的明显原因。这可能与VirtualAlloc has 64k granularity.
您可以使用 VirtualQuery 来确定哪些页面是有效的。每次您的“for 循环”前进到一个新页面时,然后调用 VirtualQuery。如果State
值为 MEM_COMMIT 并且AllocationProtect
值设置了 PAGE_EXECUTE_READ、PAGE_EXECUTE_READWRITE、PAGE_READONLY 或 PAGE_READWRITE 位之一,并且AllocatonProtect
值没有设置 PAGE_GUARD 位,那么您知道该页面存在并且是可读的。如果没有,那么您可以使用 RegionSize
值跳过该页面,以及其后具有相同状态的每个页面。
您还可以解析 0x77df0000 处的 PECOFF 标头以找出这些部分的加载位置,但这要复杂一些。
【讨论】:
那么您建议如何处理实际代码中的问题?假设我有一个For loop
用于整个模块内存地址。我需要自己读取每个字节。
@RE-Beginner 我更新了我的答案,解释了如何使用 VirtualQuery。
作为对任何试图在此处进行 RE 内容的人的旁注,关于 ntdll.dll 的许多事情都特别违反了 pecoff 规范。是龙。以上是关于读取 ntdll.dll + offset 会导致访问冲突的主要内容,如果未能解决你的问题,请参考以下文章
使用 EasyHook (c#) 从 ntdll.dll 挂钩 NtCreateFile API