Tải bản đầy đủ (.docx) (19 trang)

TÌM HIỂU CƠ CHẾ QUẢN LÝ HEAP (HEAP MANAGER) AN TOÀN HỆ ĐIỀU HÀNH

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (220.69 KB, 19 trang )

BAN CƠ YẾU CHÍNH PHỦ
HỌC VIỆN KỸ THUẬT MẬT MÃ

BÀI TẬP LỚN
Môn AN TOÀN HỆ ĐIỀU HÀNH
ĐỀ TÀI: TÌM HIỂU CƠ CHẾ QUẢN LÝ HEAP
(HEAP MANAGER)
Ngành: Công nghệ thông tin
Chuyên ngành: An toàn thông tin
Họ và tên học viên:

Đỗ Đức Thành
Nguyễn Văn Tân
Nguyễn Văn Minh
Nguyễn Quang Tuấn

Lớp:

L03

Giáo viên hướng dẫn : Đồng Thị Thùy Linh

1


LỜI MỞ ĐẦU
Heap là một trong 2 vùng nhớ rất quan trọng của máy tính. Vì vậy, nhóm
em nhận đề tài tìm hiểu về cơ chế quản lý heap để hiểu thêm về heap và cơ
chế quản lý heap.
Nội dung của đề tài bao gồm:
Chương 1: Tìm hiểu chung về heap.


Chương 2: Tìm hiểu về cơ chế quản lý heap.
Chương 3: Kết luận.
Nhóm em xin cảm ơn cô đã giúp nhóm em trong quá trình tìm tài liệu để
làm đề tài này.

2


MỤC LỤC

3


CHƯƠNG 1: TÌM HIỂU CHUNG VỀ HEAP
1.1. Heap là gì?
Heap là vùng nhớ được dùng để cấp phát và giải phóng các đối tượng một
cách linh hoạt cho các chương trình sử dụng. Heap hoạt động khi:
1. Số lượng và kích thước của các đối tượng cần thiết của chương
trình không đượ biết trước thời hạn.
2. Đối tượng quá lớn để khớp với trình cấp phát stack.
Một heap sử dụng các bộ phận của bộ nhớ bên ngoài những gì được cấp
phát cho các code và stack trong thời gian chạy. Hình dưới đây cho thấy các
lớp khác nhau của bộ cấp phát heap.

Hình 1.1 : Các lớp khác nhau của bộ cấp phát heap.
GlobalAlloc / GlobalFree: Gọi trực tiếp các heap mặc định cho mỗi tiến
trình.
LocalAlloc / LocalFree: Gọi trực tiếp các heap mặc định cho mỗi tiến
trình.
4



COM's IMalloc allocator (or CoTaskMemAlloc / CoTaskMemFree):
Chức năng sử dụng heap trên mỗi tiến trình mặ định. Tự động sử dụng bộ cấp
phát Component Object Model (COM) và các yêu cầu sử dụng heap cho mỗi
tiến trình.
C/C++ Run-time (CRT) allocator: Cung cấp malloc() và free() cũng
như các toán tử new và delete.
1.2. Phân loại heap
Mỗi tiến trình trong Windows có một heap được gọi là default heap. Các
tiến trình cũng có thể có nhiều dynamic heaps khác như mong muốn, chỉ đơn
giản bằng cách tạo và phá hủy chúng ngay lập tức. Hệ thống sử dụng heap
mặc định cho tất cả các hàm/chức năng quản lý bộ nhớ cục bộ và toàn cục, và
thư viện run-time C sử dụng heap mặc định để hỗ trợ các hàm/chức năng
malloc. Các hàm/chức năng bộ nhớ heap, cái mà biểu thị 1 heap riêng bởi
cách xử lý của nó, sử dụng dynamic heap.
Các heaps mặc định và động về cơ bản là giống nhau, nhưng heap mặc
định có đặc tính đặc biệt của việc nhận dạng được như là mặc định. Đây là
cách thư viện run-time C và hệ thống xác định heap để phân
bổ. Hàm GetProcessHeap trả về một heap mặc định để xử lý tiến trình. Vì
các hàm như GlobalAlloc hoặc malloc được thực thi trong ngữ cảnh của
luồng gọi chúng, chúng chỉ đơn giản gọi GetProcessHeap để lấy một đến
heap mặc định, và sau đó quản lý bộ nhớ một cách phù hợp.
1.3. Vai trò của heap
Hệ thống con Windows trên Windows NT cung cấp các chức năng quản
lý bộ nhớ cấp cao khiến cho các ứng dụng dễ dàng xây dựng các cấu trúc dữ
liệu động, cung cấp khả năng tương thích với các phiên bản trước của
Windows và tạo bộ đệm và bộ nhớ tạm thời cho các chức năng của hệ
thống. Các chức năng quản lý bộ nhớ này sẽ trả về các chốt xử lý và trỏ tới
các khối bộ nhớ được phân bổ trong thời gian chạy và được quản lý bởi một

thực thể được gọi là heap . Chức năng chính của heap là quản lý hiệu suất bộ
nhớ và không gian địa chỉ của một tiến trình cho một ứng dụng.
Ở một mức độ cao hơn, việc xem xét heap hoàn toàn không ảnh hưởng
tới việc ứng dụng định làm gì với bộ nhớ của nó và địa chỉ rỗng. Tuy nhiên,
heap đã cung cấp một bộ các chức năng mạnh mẽ cho phép các nhà phát triển
bỏ qua một số chi tiết tốt hơn về tài nguyên hệ thống (như sự khác biệt giữa
bộ nhớ dành riêng, miễn phí và cam kết) để họ có thể biến sự chú ý của họ
thành một nhiệm vụ quan trọng hơn trong tay, của việc thực hiện các ứng
dụng của họ.
5


Trong Windows NT, heaps cung cấp một hạt nhỏ hơn cho kích thước của
bộ nhớ nhỏ nhất được phân bổ bộ nhớ hơn các chức năng quản lý bộ nhớ
ảo. Các ứng dụng thường cần phải phân bổ một số byte cụ thể để đáp ứng yêu
cầu tham số hoặc hoạt động như một bộ đệm tạm thời. Ví dụ, khi nạp một tài
nguyên chuỗi với chức năng LoadString , một ứng dụng chuyển một con trỏ
tới một bộ đệm nhận được tài nguyên chuỗi. Kích thước của bộ đệm phải đủ
lớn để chứa chuỗi và một terminator null. Nếu không có trình quản lý heap,
các ứng dụng sẽ buộc phải sử dụng các chức năng quản lý bộ nhớ ảo, phân bổ
ít nhất một trang bộ nhớ cùng một lúc.

1.4. Hành vi chung của heap
Trong khi heap cung cấp hỗ trợ để quản lý các khối nhỏ hơn của bộ nhớ,
nó không có gì hơn một đoạn bộ nhớ thực hiện trong hệ thống bộ nhớ ảo
Windows NT. Do đó, các kỹ thuật mà heap sử dụng để quản lý bộ nhớ dựa
trên các chức năng quản lý bộ nhớ ảo có sẵn cho heap. Bằng chứng này được
tìm thấy trong cách heaps tự thực hiện trong một tiến trình.
Ứng dụng mẫu của ProcessWalker (PW) khám phá mỗi thành phần trong
một tiến trình, bao gồm tất cả các heap của nó. PW xác định các heap trong

một quá trình và cho thấy dung lượng của bộ nhớ dành riêng và cam kết liên
quan đến một heap cụ thể. Giống như tất cả các vùng bộ nhớ khác trong một
tiến trình, vùng nhỏ nhất của bộ nhớ cam kết trong một heap là một trang
(4096 byte).
Điều này không có nghĩa là số lượng bộ nhớ nhỏ nhất có thể được phân
bổ trong heap là 4096 byte; thay vào đó, trình quản lý heap cam kết các trang
bộ nhớ nếu cần để đáp ứng các yêu cầu phân bổ cụ thể. Ví dụ, nếu một ứng
dụng phân bổ 100 byte thông qua một cuộc gọi tới hàm GlobalAlloc , trình
quản lý heap phân bổ bộ nhớ 100 byte trong vùng cam kết của nó cho yêu cầu
này. Nếu không có đủ bộ nhớ cam kết có sẵn tại thời điểm yêu cầu, trình quản
lý heap sẽ thực hiện cam kết một trang khác để làm cho bộ nhớ có sẵn.
Nếu một ứng dụng lặp đi lặp lại phân bổ các khối 100 byte bộ nhớ, heap
sẽ cam kết thêm một trang bộ nhớ cho mỗi 40 yêu cầu đầu tiên (40 * 100 byte
= 4000 byte). Khi yêu cầu 40 lần đầu tiên cho một đoạn 100 byte, heap
manager nhận ra rằng không có đủ bộ nhớ cam kết để đáp ứng yêu cầu, do đó
nó cam kết một trang khác của bộ nhớ và sau đó hoàn thành việc phân bổ yêu
cầu. Bằng cách này, trình quản lý heap có trách nhiệm quản lý môi trường bộ
nhớ ảo hoàn toàn minh bạch của ứng dụng.
Trong thực tế, dù vậy, heap manager yêu cầu bộ nhớ bổ sung để quản lý
bộ nhớ trong heap. Vì vậy, thay vì chỉ phân bổ 100 byte theo yêu cầu, nó
6


cũng phân bổ một số không gian để quản lý từng phần cụ thể của bộ
nhớ. Kiểu bộ nhớ và kích thước của phân bổ xác định kích thước của bộ nhớ
bổ sung này.
1.5. Các vấn đề chung về hiệu suất của heap
Đây là những trở ngại phổ biến nhất mà bạn gặp phải khi làm vi ệc
với heap:
•Chậm lại như là kết quả của hoạt động phân bổ. Nó chỉ đơn

giản mất một thời gian dài để phân bổ. Lý do có khả năng nhất
của sự chậm lại là các danh sách miễn phí không có các khối, và do
đó mã thời gian chạy allocator dành chu kỳ săn tìm cho một kh ối
lượng lớn hơn miễn phí hoặc phân bổ một khối tươi từ bộ cấp
phát back-end.
•Sự

chậm lại do hoạt động tự do. Các hoạt động tự do tiêu thụ
nhiều chu kỳ hơn, chủ yếu là nếu kết hợp lại được kích
hoạt. Trong quá trình kết hợp, mỗi hoạt động tự do nên "tìm"
hàng xóm, kéo chúng ra để xây dựng một khối lớn hơn, và lắp l ại
khối lớn hơn vào danh sách miễn phí. Trong quá trình tìm kiếm,
bộ nhớ có thể bị xúc động theo thứ tự ngẫu nhiên, gây ra lỗi bộ
nhớ cache và hiệu năng làm chậm lại.

•Suy

thoái như là kết quả của cuộc tranh luận heap. Sự tranh
luận xảy ra khi hai hoặc nhiều chủ đề thử truy cập vào dữ liệu
cùng một lúc và người ta phải đợi cho người kia hoàn thành tr ước
khi có thể tiến hành. Cạnh tranh luôn luôn gây ra rắc rối; đó là vấn
đề lớn nhất mà một trong những gặp phải trên hệ thống đa. Một
ứng dụng hoặc DLL với khối lượng lớn sử dụng bộ nhớ sẽ chậm
lại khi chạy với nhiều luồng (và trên các hệ thống đa xử lý). Việc
sử dụng khóa đơn - giải pháp chung - có nghĩa là tất cả các hoạt
động sử dụng heap được tuần tự. Các serialization gây ra chủ đề
để chuyển đổi bối cảnh trong khi chờ khóa. Hãy tưởng tượng sự
suy thoái do stop-and-go tại đèn pha nhấp nháy màu đỏ nhấp
nháy.
Sự ganh đua thường dẫn đến sự chuyển đổi ngữ cảnh của ch ủ

đề và quy trình. Bối cảnh chuyển mạch rất tốn kém, nhưng thậm
chí còn tốn kém hơn là mất dữ liệu từ bộ nhớ cache của bộ x ử lý
và xây dựng lại dữ liệu đó khi sợi được đưa vào cuộc sống sau đó.

•Suy

thoái như là kết quả của tham nhũng đống. Tham nhũng xảy
ra khi ứng dụng không sử dụng khối heap đúng cách. Các tình
7


huống phổ biến bao gồm việc tăng gấp đôi hoặc sử dụng m ột
khối sau khi miễn phí, và các vấn đề rõ ràng về ghi đè v ượt quá
ranh giới khối.
•Chậm

lại như là một kết quả của allocs thường xuyên và
reallocs. Đây là một hiện tượng rất phổ biến khi bạn s ử dụng
ngôn ngữ kịch bản. Các chuỗi được phân bổ nhiều lần, phát triển
với sự phân bổ lại, và giải phóng. Đừng làm điều này. Hãy thử phân
bổ các chuỗi lớn, nếu có thể, và sử dụng bộ đệm. Một giải pháp
thay thế là giảm thiểu các hoạt động nối.

Sự ganh đua là vấn đề giới thiệu sự chậm lại trong phân bổ cũng
như hoạt động tự do. Lý tưởng nhất là chúng tôi muốn có một đống mà
không có tranh chấp và cấp phát nhanh / miễn phí. Than ôi, chẳng có
một đống mục đích chung như vậy, mặc dù nó có thể sẽ xảy ra trong
tương lai.
Trong tất cả các hệ thống máy chủ (như IIS, MSProxy, DatabaseStacks,
các máy chủ mạng, Exchange ...), khóa heap là m ột nút c ổ chai l ớn. Số bộ

vi xử lý càng lớn, thì sự tranh cãi càng tồi tệ.

8


CHƯƠNG 2: CƠ CHẾ QUẢN LÝ HEAP
Hầu hết các ứng dụng phân bổ các khối nhỏ hơn mức phân bổ tối thiểu
64-KB có thể bằng cách sử dụng các chức năng chi tiết trang như
VirtualAlloc và VirtualAllocExNuma. Việc phân bổ một khu vực rộng lớn
cho phân bổ tương đối nhỏ không phải là tối ưu từ cách sử dụng bộ nhớ và
quan điểm hiệu năng. Để giải quyết nhu cầu này, Windows cung cấp một
thành phần được gọi là heap manager, quản lý các khoản phân bổ bên trong
vùng bộ nhớ lớn hơn được dành riêng bằng chức năng phân bổ bộ nhớ theo
từng trang. Khả năng phân bổ trong trình quản lý heap tương đối nhỏ: 8 byte
trên các hệ thống 32-bit, và 16 byte trên các hệ thống 64-bit. Trình quản lý
heap đã được thiết kế để tối ưu hóa việc sử dụng và hiệu suất bộ nhớ trong
trường hợp các phân bổ nhỏ hơn.
Trình quản lý heap tồn tại ở hai nơi: Ntdll.dll và Ntoskrnl.exe. Các API hệ
thống con (chẳng hạn như các API của Windows heap) gọi các hàm trong
Ntdll, và các thành phần điều hành khác nhau và trình điều khiển thiết bị gọi
hàm trong Ntoskrnl. Các giao diện của nó (cố định đầu với Rtl) chỉ có sẵn để
sử dụng trong các thành phần Windows bên trong hoặc các trình điều khiển
thiết bị hạt nhân. Các giao diện Windows API đã được ghi lại để heap (tiền tố
với Heap) là chuyển tiếp đến các chức năng có trong Ntdll.dll. Ngoài ra, các
API kế thừa (cố định đầu bằng Local hoặc Global) được cung cấp để hỗ trợ
các ứng dụng Windows cũ, cũng được gọi chung là quản lý heap, sử dụng
một số giao diện đặc biệt để hỗ trợ hành vi kế thừa. Thời gian chạy C (CRT)
cũng sử dụng trình quản lý heap khi sử dụng các chức năng như malloc, free,
và nhà điều hành mới của C++. Các chức năng heap phổ biến nhất của
Windows là:

■ HeapCreate hoặc HeapDestroy: Tạo hoặc xóa, tương ứng, một đống.
Bản dự thảo ban đầu và kích thước cam kết có thể được xác định khi tạo.
■ HeapAlloc: Phân bổ một khối heap.
■ HeapFree: Giải phóng một khối được phân bổ trước đó với HeapAlloc.
■ HeapReAlloc: Thay đổi kích thước của một phân bổ hiện có (phát triển
hoặc co lại một khối hiện có).
■ HeapLock hoặc HeapUnlock: Các điều khiển loại trừ lẫn nhau vào các
hoạt động của heap.
■ HeapWalk: Khai báo các mục và các vùng trong một đống.

9


2.1. Những loại Heap
Mỗi tiến trình có ít nhất một heap: tiến trình heap mặc định. Heap mặc
định được tạo ra khi khởi động quá trình và không bao giờ bị xóa trong suốt
quá trình hoạt động của tiến trình. Mặc định có kích thước 1 MB, nhưng nó
có thể được làm lớn hơn bằng cách xác định kích thước bắt đầu trong tệp
hình ảnh bằng cách sử dụng cờ liên kết /HEAP. Kích thước này chỉ là dự trữ
ban đầu, tuy nhiên, nó sẽ tự động mở rộng khi cần thiết. (Bạn cũng có thể chỉ
định kích thước cam kết ban đầu trong tệp hình ảnh.)
Heap mặc định có thể được sử dụng một cách rõ ràng bởi một chương
trình hoặc ngầm sử dụng bởi một số chức năng Windows nội bộ. Một ứng
dụng có thể truy vấn heap quá trình mặc định bằng cách thực hiện cuộc gọi
đến hàm GetProcessHeap của Windows. Các quy trình cũng có thể tạo thêm
heap riêng với chức năng HeapCreate. Khi quá trình không còn cần một heap
riêng, nó có thể phục hồi không gian địa chỉ ảo bằng cách gọi HeapDestroy.
Một mảng với tất cả các heaps được duy trì trong mỗi quá trình, và một sợi
có thể truy vấn chúng với các chức năng Windows GetProcessHeaps.
Một heap có thể quản lý phân bổ trong các vùng bộ nhớ lớn được lưu trữ

từ bộ quản lý bộ nhớ thông qua VirtualAlloc hoặc từ các đối tượng tệp ánh xạ
trên bộ nhớ ánh xạ trong không gian địa chỉ của tiến trình. Cách tiếp cận thứ
hai hiếm khi được sử dụng trong thực tế, nhưng nó phù hợp với các kịch bản
mà nội dung của các khối cần phải được chia sẻ giữa hai tiến trình hoặc giữa
một chế độ hạt nhân và một thành phần chế độ người dùng. Trình điều khiển
hệ thống con GUI Win32 (Win32k.sys) sử dụng một heap để chia sẻ GDI và
User các đối tượng với chế độ người dùng. Nếu một đống được xây dựng trên
đầu trang của vùng tệp được ánh xạ bộ nhớ, một số ràng buộc nhất định áp
dụng đối với thành phần có thể gọi hàm heap. Thứ nhất, các cấu trúc heap
bên trong sử dụng con trỏ, và do đó không cho phép remapping đến các địa
chỉ khác nhau trong các quá trình khác. Thứ hai, quá trình đồng bộ hóa qua
nhiều quá trình hoặc giữa một thành phần hạt nhân và quá trình người dùng
không được hỗ trợ bởi các chức năng heap. Ngoài ra, trong trường hợp chia
sẻ heap giữa chế độ người dùng và chế độ hạt nhân, lập bản đồ chế độ người
dùng phải là chỉ đọc để ngăn chặn mã chế độ người dùng làm hỏng các cấu
trúc nội bộ của heap, dẫn tới sự sụp đổ của hệ thống. Trình điều khiển chế độ
hạt nhân cũng chịu trách nhiệm về việc không đưa bất kỳ dữ liệu nhạy cảm
nào vào một đống chia sẻ để tránh rò rỉ nó vào chế độ người dùng.
2.2. Cấu trúc của Heap Manager
Như trong hình dưới, cấu trúc của trình quản lý Heap gồm 2 lớp: lớp tùy
chỉnh front-end và lõi Heap. Lõi heap xử lý các chức năng cơ bản và phổ biến
nhất là usermode và kernel-mode triển khai Heap. Chức năng lõi bao gồm
10


quản lý khối bên trong phân đoạn, quản lý phân đoạn, chính sách mở rộng
heap, cam kết và phân hủy bộ nhớ, và quản lý các khối lớn.

Hình 2.2 : Cấu trúc của trình quản lý Heap
Chỉ với user-mode heaps, một lớp tùy chọn front-end heap có thể tồn tại

bên trên các chức năng lõi hiện tại. Giao diện đầu cuối duy nhất được hỗ trợ
trên Windows là Low Fragmentation Heap (LFH). Tại một thời điểm, chỉ có
một lớp front-end có thể sử dụng cho một heap.
2.3. Đồng bộ hóa Heap
Trình quản lý heap theo mặc định sẽ hỗ trợ truy cập đồng thời từ nhiều
luồng. Tuy nhiên, nếu một tiến trình đơn luồng hoặc sử dụng một cơ chế bên
ngoài để đồng bộ hóa, nó có thể báo cho heap manager để tránh chi phí của
việc đồng bộ hóa bằng cách chỉ định HEAP_NO_SERIALIZE khi tạo ra heap
hoặc trên mỗi cơ sở phân bổ.
Một tiến trình cũng có thể khóa toàn bộ heap và ngăn chặn các đối tượng
khác thực hiện các hoạt động heap cho các hoạt động mà sẽ yêu cầu các trạng
thái phù hợp trên nhiều cuộc gọi heap. Ví dụ, liệt kê các khối heap trong một
heap với chức năng Windows HeapWalk yêu cầu khóa heap nếu nhiều luồng
có thể thực hiện các hoạt động heap cùng một lúc.
Nếu đồng bộ hóa heap được kích hoạt, có một khóa mỗi heap để bảo vệ
tất cả các cấu trúc heap bên trong. Trong các ứng dụng đa luồng (đặc biệt là
khi chạy trên các hệ thống đa xử lý), khóa heap có thể trở thành một điểm
11


tranh luận quan trọng. Trong trường hợp đó, hiệu suất có thể được cải thiện
bằng cách kích hoạt front-end heap, được mô tả trong phần sắp tới.
2.4. Các phân mảnh thấp Heap (The Low Fragmentation Heap – LFH)
Nhiều ứng dụng đang chạy trong Windows có mức sử dụng bộ nhớ heap
tương đối nhỏ (thường ít hơn 1 MB). Đối với loại ứng dụng này, chính sách
phù hợp nhất của bộ quản lý heap giúp duy trì bộ nhớ thấp cho mỗi tiến trình.
Tuy nhiên, chiến lược này không phù hợp cho các tiến trình lớn và những
máy đa xử lý. Trong những trường hợp này, bộ nhớ sẵn có cho việc sử dụng
heap có thể bị giảm do sự phân mảnh của heap. Hiệu suất có thể bị ảnh hưởng
trong các kịch bản chỉ với một số kích thước nhất định được sử dụng đồng

thời từ các luồng khác nhau được lên lịch chạy trên các bộ vi xử lý khác
nhau. Điều này xảy ra vì một số bộ vi xử lý cần phải sửa đổi vị trí bộ nhớ
tương tự (ví dụ như đầu của danh sách dành cho kích thước cụ thể đó) cùng
một lúc, do đó gây ra xung đột đáng kể cho dòng bộ nhớ cache tương ứng.
LFH tránh phân mảnh bằng cách quản lý khối được phân chia trong các
phạm vi khối được xác định trước khác nhau được gọi là nhóm. Khi một tiến
trình phân chia bộ nhớ từ heap, LFH sẽ chọn nhóm chứa bản đồ với khối nhỏ
nhất đủ lớn để giữ kích thước yêu cầu (khối nhỏ nhất là 8 byte). Nhóm đầu
tiên được sử dụng để phân bổ từ 1 đến 8 byte, thứ hai để phân bổ từ 9 đến 16
byte, và như vậy, cho đến khi nhóm thứ 32, được sử dụng cho phân bổ từ 249
đến 256 byte, tiếp theo là nhóm thứ 33, được sử dụng cho phân bổ giữa 257
và 272 byte, v.v ... Cuối cùng, nhóm thứ 128, là lần cuối cùng, được sử dụng
để phân bổ giữa 15,873 và 16,384 byte. (Đây được gọi là hệ thống nhị phân).
Bảng dưới đây tóm tắt các nhóm khác nhau, mức độ chi tiết và phạm vi kích
thước mà chúng ánh xạ tới.

Hình 2.3 : Bảng mức độ chi tiết và phạm vi kích thước của các nhóm

12


LFH giải quyết những vấn đề này bằng cách sử dụng trình quản lý lõi
heap và các danh sách dành riêng. Trình quản lý heap của Windows thực hiện
một thuật toán điều chỉnh tự động, có thể cho phép LFH thực hiện mặc định
theo các điều kiện nhất định, chẳng hạn như khóa cạnh tranh hoặc sự có mặt
của các phân bổ kích thước phổ biến đã cho thấy hiệu suất tốt hơn với LFH
được kích hoạt. Đối với các heap lớn, một tỷ lệ đáng kể các khoản phân bổ
thường được phân nhóm trong một số lượng tương đối nhỏ nhóm có kích
thước nhất định. Chiến lược phân bổ được sử dụng bởi LFH là để tối ưu hóa
việc sử dụng cho các mô hình này bằng cách hiệu quả các khối kích thước

tương tự.
Để giải quyết khả năng mở rộng, LFH mở rộng các cấu trúc nội bộ
thường xuyên truy cập vào một số khe gấp hai lần so với số bộ xử lý hiện tại
trên máy. Việc gán các luồng đến các khe này được thực hiện bởi một thành
phần LFH được gọi là trình quản lý mối quan hệ. Ban đầu, LFH bắt đầu sử
dụng khe đầu tiên cho việc phân bổ heap. Tuy nhiên, nếu một cuộc xung đột
được phát hiện khi truy cập vào một số dữ liệu nội bộ, LFH sẽ chuyển đổi
luồng hiện tại để sử dụng một khe khác. Những sự xung đột khác sẽ lan
truyền trên nhiều khe. Các khe này được kiểm soát cho mỗi nhóm một dung
lượng để cải thiện vùng và giảm thiểu tiêu thụ bộ nhớ tổng thể.
Ngay cả khi LFH được kích hoạt như là một front-end heap, kích thước
phân bổ ít thường xuyên hơn, thì vẫn có thể tiếp tục sử dụng các chức năng
của lõi heap để phân bổ bộ nhớ, trong khi các lớp phân bổ phổ biến nhất sẽ
được thực hiện từ LFH. LFH cũng có thể bị vô hiệu hóa bằng cách sử dụng
API HeapSetInformation với class HeapCompatibilityInformation.
2.5. Tính năng bảo mật của Heap
Khi việc quản lý Heap được phát triển, nó đã có vai trò quan trọng trong
phát hiện sớm các lỗi sử dụng heap và trong làm giảm ảnh hưởng của các
khai thác tiềm tàng trên heap-based. Các biện pháp này tồn tại để làm giảm
khả năng ảnh hưởng của các lỗ hổng tiềm tàng trong các ứng dụng. Siêu dữ
liệu được sử dụng bởi các heap để quản lý nội bộ được đóng gói với mức độ
cao ngẫu nhiên để làm nó khó khăn cho nỗ lực khai thác để vá các cấu trúc
bên trong để ngăn ngừa các xung đột hoặc che giấu các nỗ lực tấn công. Các
khối này cũng phải tuân theo cơ chế kiểm tra tính toàn vẹn trên header để
phát hiện các lỗi đơn giản như tràn bộ đệm. Cuối cùng heap cũng sử dụng
một mức độ nhỏ ngẫu nhiên của địa chỉ cơ bản (hoặc xử lý). Bằng việc sử
dụng API HeapSetInformation và lớp HeapEnableTerminationOnCorruption,
các tiến trình có thể chọn để hủy bỏ tự động trong trường hợp phát hiện các
mâu thuẫn để tránh thực thi mã không tin cậy.


13


Như một kết quả của các khối siêu dữ liệu ngẫu nhiên, sử dụng trình gỡ
rối để đơn giản kết xuất một khối header như một vùng của bộ nhớ là không
cần thiết. Ví dụ, kích thước của các khối và cho dù nó đang sử dụng hoặc là
không dễ dàng phát hiện từ một kết xuất thường xuyên. Tương tự với các
khối LFH; chúng có một loại siêu dữ liệu khác nhau được lưu trữ ở phần
header, một phần ngẫu nhiên tương tự.
Để kết xuất các thông tin chi tiết này, lệnh !heap –i trong trình gỡ rối thực
hiện tất các công việc để lấy các trường siêu dữ liệu từ các khối, gắn cờ kiểm
tra toàn vẹn hoặc danh sách các mâu thuẫn nếu chúng tồn tại. Lệnh hoạt động
cho cả LFH và các khối heap thường lệ. Tổng kích thước các khối, yêu cầu
kích thước người sử dụng, các segment sở hữu của khối cũng như kiểm tra
tình toàn vẹn từng phần có đang có sẵn trong đầu ra, như thể hiện trong các
mẫu sau đây. Bởi vì các thuật toán ngẫu nhiên sử dungk heap granularity, nên
lệnh !heap –i nên được sử dụng chỉ trong các bối cảnh thích hợp của heap bao
gồm các khối. Trong ví dụ, heap xử lý là 0x001a0000. Nếu bối cảnh của các
heap là khác nhau thì việc giải mã của header sẽ là không chính xác. Để thiết
lập đúng ngữ cảnh, lệnh !heap –i với heap xử lý như một đối số cần được
thực hiện trước.
0:000> !heap -i 001a0000
Heap context set to the heap 0x001a0000
0:000> !heap -i 1e2570
Detailed information for block entry 001e2570
Assumed heap : 0x001a0000 (Use !heap -i NewHeapHandle to change)
Header content : 0x1570F4EC 0x0C0015BE (decoded : 0x07010006
0x0C00000D)
Owning segment : 0x001a0000 (offset 0)
Block flags : 0x1 (busy )

Total block size : 0x6 units (0x30 bytes)
Requested size : 0x24 bytes (unused 0xc bytes)
Previous block size: 0xd units (0x68 bytes)
Block CRC : OK - 0x7
Previous block : 0x001e2508
Next block : 0x001e25a0
2.6. Tính năng gỡ lỗi Heap
Trình quản lý heap ấn định 8 byte được sử dụng để lưu trữ siêu dữ liệu
nội bộ như là một điểm kiểm tra tính nhất quán, làm cho các lỗi sử dụng heap

14


tiềm ẩn trở nên rõ ràng hơn và cũng bao gồm một số tính năng để giúp phát
hiện lỗi bằng cách sử dụng các hàm heap sau:
Bật kiểm tra cuối: sự kết thúc của mỗi chuỗi mang một chữ ký đã được
kiểm tra khi khối được tạo ra. Nếu lỗi tràn bộ đệm phá hủy một phần hoặc
toàn bộ chữ ký, heap sẽ báo cáo lại lỗi này.
Bật kiểm tra miễn phí: một khối heap tự do được lấp đầy bằng các mẫu
kiểm tra tại nhiều điểm khác nhau khi trình quản lý heap cần truy cập vào
khối (chẳng hạn như loại bỏ các danh sách tự do để đáp ứng yêu cầu phân
bổ). Nếu các tiến trình tiếp tục ghi vào các khối sau khi đã giải phóng nó, thì
trình quản lý heap sẽ phát hiện các thay đổi trong mẫu và các lỗi sẽ được báo
cáo.
Kiểm tra tham số: hàm này bao gồm chức năng kiểm tra bao quát các
tham số truyền tới các hàm heap
Xác nhận heap: toàn bộ heap được xác nhận tại mỗi lệnh heap.
Gắn thẻ heap và hỗ trợ dò ngăn xếp: hàm này hỗ trợ xác định các thẻ
và/ hoặc thu thập dò ngăn xếp ở chế độ người dùng cho các lệnh gọi heap để
thu hẹp các nguyên nhân có thể xảy ra một lỗi heap

Ba tùy chọn đầu tiên được phép mặc định nếu bộ nạp phát hiện một tiến
trình được bắt đầu dưới sự kiểm soát của một trình gỡ rối. (Một trình gỡ rối
có thể ghi đè lên các hành vi này và tắt các tính năng này.) Các tính năng gỡ
lỗi có thể được chỉ định cho một image thực thi bằng cách thiết lập nhiều cờ
gỡ lỗi khác nhau trong image header sử dụng công cụ Gflags. ( Xem phần
“Windows Global Flags” chương 3 phần 1). Hoặc các tùy chọn gỡ rối có thể
được phép sử dụng lệnh !heap trong các trình gỡ rối chuẩn của Windows.
(Xem trợ giúp trình gỡ lỗi để biết thêm thông tin.)
Bật tùy chọn gỡ rối heap ảnh hưởng tới tất các các heap trong tiến trình.
Ngoài ra nếu một trong bất kỳ các tùy chọn được kích hoạt, LFH sẽ tự động
bị vô hiệu hóa và các heap lõi sẽ được sử dụng(với các tùy chọn gỡ lỗi được
yêu cầu bật). LFH cũng không được sử dụng cho các heap không thể mở rộng
được(bởi vì các phần phụ được thêm vào cấu trúc heap hiện có) hoặc các
heap mà không cho phép tuần tự.
2.7. Pageheap
Bởi vì các tùy chọn kiểm tra cuối và kiểm tra tự do được trình bày ở phần
trước đó có thể phát hiện ra các lỗi xảy ra trước khi phát hiện vấn đề, một khả
năng gỡ lỗi heap được bổ sung, được gọi là pageheap , được cung cấp nhằm
điều khiển tất cả hoặc một phần các lệnh gọi heap đến một trình quản lý heap
15


khác. Pageheap được kích hoạt bằng cách sử dụng công cụ Gflags (nó là một
phần của các công cụ gỡ lỗi cho Windows ). Khi được kích hoạt, trình quản
lý heap sắp xếp phân bổ ở cuối các trang và để riêng ngay trang kế tiếp. Do
các trang dành riêng không thể truy cập được, nếu xảy ra sự tràn bộ đệm sẽ
gây ra sự vi phạm quyền truy cập, làm cho việc phát hiện mã vi phạm trở nên
dễ dàng hơn. Theo tùy chọn, pageheap cho phép đặt các khối ở đầu trang, với
trang được đặt trước, để phát hiện các vấn đề về tràn bộ đệm.(Đây là sự biến
cố hiếm hoi.) Pageheap cũng có thể bảo vệ bất các trang được giải phóng

khỏi bất kỳ truy cập nào liên quan tới các khối heap sau khi chúng được giải
phóng.
Lưu ý rằng việc sử dụng pageheap có thể dẫn tới việc hết không gian địa
chỉ. Ngoài ra, hiệu suất có thể chịu ảnh hưởng như một kết quả của sự gia
tăng liên quan tới các trang không yêu cầu, mất vị trí, các chi phí bổ sung gây
ra bởi các lệnh gọi thường xuyên để xác nhận các cấu trúc heap. Một tiến
trình có thể làm giảm tác động bằng cách xác định pageheap chỉ được sử
dụng cho các khối có kích thước nào đó, dải địa chỉ, và/hoặc DLLs gốc.
2.8. Fault Tolerant Heap
Sự hư hỏng của siêu dữ liệu heap đã được Microsoft xác định là một
trong những nguyên nhân phổ biến nhất của ứng dụng. Windows bao gồm
một tính năng gọi là The fault tolerant heap, hay FTH, nhằm giảm thiểu các
vấn đề và cung cấp tài nguyên giải quyết các vấn đề tốt hơn cho các nhà phát
triển. The fault tolerant heap được thực hiện trong hai phần chính là : thành
phần phát hiện, hoặc máy chủ FTH, hoặc thành phần giảm nhẹ, hoặc máy
trạm FTH
Thành phần phát hiện là một DLL, Fthsvc.dl, nó được nạp bởi dịch vụ
Security Center Windows (Wscsvc.dll, nó chạy trong các tiến trình chia sẻ
dịch vụ dưới các dịch vụ tài khoản cục bộ). Nó được thông báo về sự cố của
ứng dụng bởi dịch vụ báo lỗi của Windows
Khi một ứng dụng bị treo trong Ntdll.dll, với tình trạng lỗi cho biết một
trong những vi phạm truy cập hoặc một ngoại lệ lỗi heap, nếu nó không phải
trong danh sách “theo dõi” ứng dụng của dịch vụ FTH, thì dịch vụ tạo ra một
“vé” cho ứng dụng để giữ dữ liệu của FTH. Nếu ứng dụng sau đó xảy ra lỗi
nhiều hơn bốn lần trong một giờ, thì dịch vụ FTH sẽ cấu hình ứng dụng để
máy trạm FTH sử dụng trong tương lai.
Máy trạm FTH là một ứng dụng tương thích với shim. Cơ chế này được
sử dụng từ Windows XP để cho phép các ứng dụng phụ thuộc vào các hành vi
cụ thể của các hệ thống Windows cũ để chạy trên các hệ thống sau này. Trong
trường hợp này, cơ chế shim chặn các lệnh thường xuyên gọi tới heap và

16


chuyển hướng chúng tới mã riêng của nó. Mã FTH thực hiện một số “biện
pháp giảm nhẹ” cố gắng cho các ứng dụng tồn tại bất kể các lỗi liên quan
đến heap khác nhau.
Ví dụ, để bảo vệ chống lại lỗi tràn bộ đệm nhỏ, FTH thêm 8 byte đệm và
một khu vực dành riêng FTH cho mỗi lần cấp phát. Để giải quyết một tình
huống phổ biến trong đó một khối heap được truy cập sau khi nó được giải
phóng, lệnh Heapfree được thực hiện chỉ sau một trễ: “giải phóng” các khối
được đặt trong một danh sách và chỉ giải phóng khi tổng kích thước các khối
trong danh sách lớn hơn 4MB. Các nỗ lực để giải phóng các vùng không thực
sự thuộc về heap hoặc không là một phần của heap được xác định bởi đối số
heap handle đến HeapFree , chỉ đơn giản là bỏ qua. Ngoài ra, không có một
khối nào thực sự được giải phóng sau khi thoát hoặc RtlExitUserProcess đã
gọi.
Máy chủ FTH tiếp tục theo dõi tỷ lệ lỗi của ứng dụng sau khi các biện
pháp giảm thiểu đã được cài đặt. Nếu tỷ lệ thất bại không được cải thiện thì
các biện pháp giảm thiểu sẽ được loại bỏ.
Hoạt động của the fault tolerant heap có thể được quan sát trong Event
Viewer. Gõ eventvwr.msc tại Run prompt, và sau đó điều hướng trong ngăn
bên trái để đến Event Viewer, các ứng dụng và các bản ghi dịch vụ,
Microsoft, Windows, Fault-Tolerant-Heap. Nhấp vào nhật ký hoạt động. Nó
có thể bị tắt hoàn toàn trong registry: HKLM\Software\Microsoft\FTH, đặt
giá trị Bật thành 0
FTH không hoạt động bình thường trên các dịch vụ, chỉ các dịch vụ, và
nó bị vô hiệu hóa trên các máy chủ Windows vì hiệu suất. Một quản trị viên
hệ thống có thể tự thực hiện shim hoặc dịch vụ thực thi bằng cách sử dụng
Application Compatibility Toolkit(Bộ công cụ tương thích ứng dụng)


17


KẾT LUẬN
Qua đề tài này, nhóm em đã tìm hiểu được heap là gì và đặc biệt là cơ chế
quản lý heap.
Tuy nhiên, do thời gian hạn chế và trình độ hiểu biết của bản thân nên
nhóm chúng em chưa thể hiểu sâu được, bài báo cáo vẫn chỉ mang tính chất
học hỏi, tìm hiểu và chưa thể đầy đủ hết được. Nhưng qua bài báo cáo này,
các thành viên trong nhóm đã học hỏi được nhiều kinh nghiệm trong quá
trình làm việc theo nhóm, đồng thời cũng bổ sung kiến thức cho bản thân.

18


TÀI LIỆU THAM KHẢO
[1] “ Heap: Pleasures and Pains”, />[3] “Managing heap memory”
us/library/ms810603.aspx

, />
[2] “Windows Internals, Sixth Edition, Part 2 eBook”, Mark
Russinovich,
David
A.
Solomon,
Alex
Ionescu,
/>%202_6th%20Edition.pdf

19




×