LỜI MỞ ĐẦU 3
CHƯƠNG 1: TÌM HIỂU VỀ LẬP TRÌNH WINDOWS 4
I. Khái quát về lập trình trong Windows 5
II. Thông điệp và xử lý thông điệp 7
III. Giao diện thiết bị đồ họa GDI 11
IV. Cửa sổ trong Windows 15
V. Chương trình Windows tiếp nhận thông điệp chuột 22
CHƯƠNG 2: TÌM HIỂU VỀ HOOK 26
1 - Chuỗi hook 27
2 - Thủ tục hook 27
3 - Các loại hook 28
4 - Sử dụng hook 30
5 - Hook trong Windows 3.x 31
6 - Giới thiệu một số hàm liên quan đến hook 33
CHƯƠNG 3: KỸ THUẬT OVERRIDE HÀM API 36
I. Khái quát về kỹ thuật override 37
II. Lý do sử dụng kỹ thuật override trong lập trình Windows 37
III. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 16bits 38
IV. Cơ chế hoạt động và quản lý bộ nhớ trên Windows 32bits 41
V. Hiện thực kỹ thuật override trên Windows 16bits 45
VI. Một số hàm được sử dụng trong kỹ thuật override 50
CHƯƠNG 4: KẾT XUẤT VĂN BẢN TRONG WINDOWS 54
I. Kết xuất văn bản trong Windows 55
II. Các hàm căn bản để kết xuất văn bản 55
CHƯƠNG 5: PHÂN TÍCH VÀ THIẾT KẾ CHƯƠNG TRÌNH 66
I. Phân tích vấn đề 67
II. Thiết kế chương trình 68
III. Giới thiệu một số hàm có liên quan 78
IV. Giới thiệu một số cấu trúc dữ liệu có liên quan 92
KẾT QUẢ VÀ HƯỚNG PHÁT TRIỂN 97
98 trang |
Chia sẻ: huong.duong | Lượt xem: 1241 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Đề tài Nghiên cứu các phương pháp nhận dạng từ dưới cursor mouse trên Desktop Windows, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
RAM wParam;
LPARAM lParam;
- Hàm CallNextHookEx function chuyển các thông tin hook đến hàm xử lý hook kế tiếp trong hook chain.
- Thông số
hHook Chỉ định hook handle
nCode Chỉ định hook code để gởi đến hook kế tiếp. Hàm xử lý hook dùng giá trị này để chỉ định xử lý thông điệp được gởi từ hook thế nào.
wParam Chỉ định 16 bits thông tin mở rộng của thông điệp
lParam Chỉ định 32 bits thông tin mở rộng của thông điệp
- Giá trị trả về: Giá trị trả về là kết quả của quá trình xử lý và tùy thuộc vào thông số nCode.
Chương 3:
KỸ THUẬT OVERRIDEHÀM API
I - Khái quát về kỹ thuật override:
Override có nghĩa là: Thay thế một giá trị lúc run-time cho một giá trị đã có trong tập tin hoặc trong chương trình. Hoặc tạo ra một đáp ứng lúc run-time thay cho tình huống dự kiến trong chương trình.
Đối với các hàm giao tiếp trong môi trường Windows thì khi Windows gọi đến các DLL (Dynamic Link Library – Thư viện liên kết động) tại các điểm nhập của các hàm Kernel, User, GDI… để xử lý các hàm được gọi trong ứng dụng thì chính ở thời điểm này ta có thể chen vào để có thể thực hiện việc hoàn tất bất kỳ thao tác xử lý gì. Việc chen vào ở thời điểm đó sẽ có 2 cách như sau dựa vào thời điểm để chen vào:
- Cách 1 : chen vào trước khi hàm API bị gọi được thi hành (front-end processing)
- Cách 2 : sau khi hàm API đã kết thúc việc thực thi thì ta cho chen vào dẫn đến việc thực thi một thao tác gì hoặc một công việc theo yêu cầu của ta (back-end processing).
Như vậy override các hàm thuộc giao tiếp Windows là một kỹ thuật cho phép developer can thiệp vào tiến trình gọi hàm API nhằm thực hiện một thao tác, một công việc gì đó theo mục đích của developer trước khi quá trình thực thi hàm API bắt đầu (theo cách 1) hoặc là ngay sau khi đã kết thúc việc thực thi hàm API (theo cách 2).
II - Lý do để sử dụng kỹ thuật override trong lập trình trên môi trường Windows:
Như vậy nếu sử dụng kỹ thuật override thì developer có thể lập trình để chen vào tiến trình thực thi các hành vi, thao tác xử lý riêng của mình bằng cách đón đợi thông báo gọi hàm API tương ứng từ chương trình ứng dụng và chuyển hướng điều khiển cho thực thi đoạn chương trình riêng đó mà không cần sửa đổi, biên dịch lại chương trình ứng dụng. Khi không cần thiết thì cơ chế override có thể được tắt đi và chương trình ứng dụng có thể trở về thực thi bình thường đúng chức năng của mình . Ngoài ra, override các hàm Windows API là một quá trình can thiệp động vào hệ thống nên kỹ thuật override là rất cần thiết trong trường hợp developer muốn bổ xung thêm hoặc sửa đổi một số tính năng hoạt động của tất cả hay chỉ một số ứng dụng đang chạy trong hệ thống mà không cần phải sửa chữa hay biên dịch lại các chương trình nguồn của ứng dụng. Mà dù có muốn thì developer cũng không thể làm được điều này bởi vì Windows không cho phép thâm nhập cũng như công bố bản mã nguồn của các ứng dụng đó. Từ đó ta thấy override xử lý các tình huống này hoàn toàn một cách tự động. Như vậy, trong Windows thì kỹ thuật override là một trong những kỹ thuật có thể được dùng như là phương tiện nâng cao tính năng của chương trình ứng dụng mà vẫn được sự chấp thuận của hệ thống Windows.
Một vài chương trình xử lý ngắt trong hệ điều hành DOS có thể được override bởi đoạn chương trình xử lý ngắt riêng của user bằng cách gán địa chỉ bộ nhớ nơi mà chương trình xử lý ngắt mới vào bảng vector ngắt tương ứng với số hiệu ngắt đồng thời lưu giữ địa chỉ của chương trình xử lý ngắt để trở về hoặc phục hồi bảng vector ngắt khi cần thiết. Mỗi khi có ngắt xảy ra hệ thống sẽ tham khảo bảng vector ngắt để xác định địa chỉ của chương trình phục vụ cần thi hành và chuyển điều khiển đến đó, lúc này đoạn chương trình của user có địa chỉ đặt trong bảng vector ngắt mới sẽ thực thi. Điểm trở về của chương trình sẽ do user quyết định: chuyển điều khiển đến lệnh kế tiếp sau lệnh đã xảy ra ngắt hoặc tiếp tục thi hành lệnh ngắt cũ rồi mới trở về. Từ đó trong Windows chúng ta sẽ tìm cách trỏ tới địa chỉ đoạn chương trình sẽ override hàm API thay vì hệ thống phải chuyển điều khiển tới địa chỉ đoạn mã thực sự của hàm API mỗi khi hàm được gọi.
Tuy nhiên do cơ chế quản lý bộ nhớ của Windows khác với DOS nên chúng ta phải tìm hiểu thật kỹ về cơ chế quản lý bộ nhớ của Windows để có thể tìm ra được giải pháp kỹ thuật thật tốt cho vấn đề override. Đặc biệt chúng ta cũng cần tìm hiểu sự khác nhau giữa Windows 16-bit và Windows 32-bit.
III - Cơ chế hoạt động và quản lý bộ nhớ trên Windows 16bits :
Windows 16bits tự động chạy ở chế độ “386 enhanced mode” ở các máy 386, bộ nhớ tối thiểu 2MB. Đó thực chất là chế độ standard với 2 đặc tính bổ sung:
Windows dùng các thanh ghi trang của 386 để hiện thực bộ nhớ ảo
Windows sử dụng chế độ ảo 8086 của 386 để đáp ứng chế độ đa nhiệm MS-DOS.
Chế độ 386 enhanced và chế độ standard đem lại cho Windows những lợi ích từ cơ chế bảo vệ (protected mode) của các bộ vi xử lý 286, 386.
Bộ nhớ mở rộng (extended memory) được bổ sung trực tiếp vào bộ nhớ conventional (conventional memory) và được sử dụng như một khối nhớ liên tục. Cơ chế bảo vệ còn cung cấp các hỗ trợ đặc biệt về quản lý bộ nhớ mà ở chế độ thực không có như việc áp buộc các truy xuất bộ nhớ phải tuân thủ một số quy luật nhằm trợ giúp đảm bảo tính toàn vẹn của mỗi chương trình, của mỗi dữ liệu của chương trình và của chính bản thân hệ thống.
Các ứng dụng Windows trong chế độ này có thể truy xuất đến một vùng nào đó trên đĩa cứng và sử dụng nó như một phần của bộ nhớ. Để truy xuất đúng phần địa chỉ ảo này Windows có bộ quản lý bộ nhớ ảo VMM (Virtual Memory Manager), nó làm việc cùng với phần cứng phân trang được thiết kế sẵn trong con 386. Trong chế độ này, không gian địa chỉ có thể lên gấp 4 lần kích thước bộ nhớ vật lý khả dụng.
Chế độ bảo vệ (protected mode): là trạng thái của bộ vi xử lý quy định một số quy luật khi bộ nhớ được đánh địa chỉ nhằm làm giảm những rủi ro mà chương trình có thể ghi đè phần bộ nhớ không thuộc về nó. Trong chế độ bảo vệ một chương trình sẽ dùng một segment gồm 2 phần: segment identifier và offset để đánh địa chỉ bộ nhớ. Sự chuyển đổi từ địa chỉ luận lý sang địa chỉ vật lý như sau: bộ vi xử lý sẽ tham khảo các bảng miêu tả (descriptor table) (bảng chứa dữ liệu đặc biệt) được hệ điều hành khởi tạo và quản lý. Có 2 loại: bảng miêu tả toàn cục GDT (Global Descriptor Tables) và bảng miêu tả cục bộ LDT (Local Descriptor Table). Một bảng miêu tả gồm một mảng các mẫu tin về thông tin của segment được gọi là bộ miêu tả phân đoạn (segment selector). Phần địa chỉ bộ nhớ mà chúng ta gọi là segment identifier được tham khảo đến như là một bộ chọn phân đoạn (segment selector). Một segment selector là một chỉ số vào mảng các bộ miêu tả tạo nên bảng miêu tả, nó xác định segment descriptor cung cấp chi tiết cần thiết để truy xuất phân đoạn dữ liệu.
Khi chương trình tham chiếu đến một vị trí nhớ, CPU sẽ nạp segment descriptor vào các thanh ghi đặc biệt để xác định địa chỉ vật lý của segment sau đó offset được cộng vào địa chỉ nền (base address) để truy xuất đến các byte bộ nhớ mong muốn.
Cấu trúc của bộ chọn chế độ bảo vệ (protected mode selector): chỉ có 13 trong số 16 bit giá trị segment được dùng như chỉ số của bảng miêu tả, 3 bit còn lại chia thành 2 phần quan trọng trong sơ đồ địa chỉ hóa và cơ chế bảo vệ. Bit 2 là cờ báo bảng miêu tả nào đang được dùng cho phép hệ điều hành thiết lập không gian địa chỉ của chương trình bằng cách dùng 2 bảng miêu tả: GDT bao hàm toàn bộ bộ nhớ được chia sẻ cho toàn hệ thống còn LDT là không gian địa chỉ riêng của chương trình. Bit 0 và bit 1 mô tả mức đặc quyền yêu cầu của phân đoạn RPL (requested privilege level), chúng được phần mềm hệ điều hành thiết lập để khởi tạo và ép buộc sơ đồ bảo vệ bộ nhớ với 4 mức đặc quyền (0,1,2,3): mức 0 là cao nhất dành riêng cho hầu hết phần mềm hệ điều hành tin cậy. Các chương trình và thư viện Windows được đặc thường trú ở mức đặc quyền thấp nhất – vành 3 để giải phóng và trao các mức đặc quyền cao hơn cho các thành phần khác của hệ điều hành.
Trong chế độ hỗ trợ bộ nhớ ảo của Windows: chỉ có trong chế độ 386 enhanced và cùng làm việc bên cạnh cơ chế bảo vệ. Các byte dữ liệu cần làm việc được xác định giống như ở chế độ bảo vệ bình thường nhưng khác ở chỗ cách dịch địa chỉ base+offset. Trong chế độ bảo vệ bình thường địa chỉ bộ nhớ dịch ra là địa chỉ vật lý. Nhưng trong chế độ 386 enhanced phần cứng phân trang được thiết kế sẵn trong bộ vi xử lý Intel 80386 sẽ được kích hoạt cho phép địa chỉ được xem như là một địa chỉ ảo. Các giá trị segment và offset sẽ được giải mã để thành không gian địa chỉ ảo. Không gian địa chỉ ảo này được phân thành các trang nhớ 4K, mỗi trang này có thể hoặc nằm trên bộ nhớ vật lý hoặc nằm trong tập tin hoán chuyển trên đĩa. Khi một tham khảo được thiết lập đến một vị trí thường trú trên đĩa, một lỗi trang sẽ được bật, là một ngắt nội tới CPU. Ngay lúc này, trình quản lý bộ nhớ ảo sẽ đọc trang nhớ mong muốn từ đĩa vào để truy xuất được dữ liệu. Chỉ thị bật lỗi trang sẽ được khởi động lại và cơ chế phân trang hoàn toàn trong suốt với phần mềm.
Sử dụng bộ nhớ:
Sử dụng các khối bộ nhớ: trong Windows bộ nhớ được quản lý theo khối, có thể di chuyển và huỷ bỏ (discardable) được. Mỗi khối nhớ di chuyển được sẽ không có địa chỉ cố định nên Windows có thể di chuyển nó đến vị trí mới và cũng có thể tận dụng tối đa phần bộ nhớ còn lại. Đối với khối nhớ hủy bỏ được Windows có thể hủy nó để cấp cho nhu cầu khác và ứng dụng có thể nạp trở lại dữ liệu khi cần thiết. Khi xin cấp một khối nhớ thì user sẽ nhận từ windows một handle bộ nhớ , dùng handle để lấy địa chỉ khối nhớ khi cần truy xuất, trong khi đang cập nhật khối nhớ thì handle phải được khóa lại để khối nhớ không di chuyển được, khi cập nhật xong thì mở khóa cho handle để Windows có thể di chuyển được.
Sử dụng bộ nhớ toàn cục (Global Memory): Bộ nhớ toàn cục gồm bộ nhớ của máy tính được sử dụng cho các ứng dụng và thư viện của Windows. Ứng dụng có thể xin cấp bộ nhớ lớn tuỳ ý phụ thuộc vào bộ nhớ toàn cục còn lại.
Sử dụng bộ nhớ cục bộ (Local Memory): nhằm đáp ứng nhu cầu cấp phát những đối tượng kích thước nhỏ, nhưng không được vượt quá 64 KB.
IV – Cơ chế hoạt động và quản lý bộ nhớ trong Windows 32bits:
Windows 32bits sử dụng mô hình bộ nhớ phẳng 4GB đã loại trừ được nhiều vấn đề nảy sinh trong hệ điều hành DOS bởi việc thay thế kiến trúc bộ nhớ phân trang thay cho kiến trúc bộ nhớ phân đoạn vốn chậm chạp.
Mỗi ứng dụng DOS chạy trong máy ảo VM (Virtual Machine) của nó. Điều này tạo cho mỗi quá trình DOS một mức bảo vệ khỏi các quá trình khác và gia tăng lượng vùng nhớ thấp khả dụng.
Việc sử dụng bộ nhớ được điều khiển bởi các quá trình VxD 32 bit làm gia tăng tốc độ xử lý. Cả hai trình VCACHE và VMM là các quá trình 32 bit làm giảm thiểu tổng phí và gia tăng tốc độ cho việc đánh địa chỉ và việc hoán đổi thông tin giữa bộ nhớ và đĩa.
Windows 32bits chỉ có thể hoạt động trên hệ thống 386 trở lên do yêu cầu phải có phần cứng hỗ trợ sơ đồ địa chỉ hóa 32 bit và cơ chế phân trang bộ nhớ.
Kiến trúc bộ nhớ:
Kiến trúc bộ nhớ của Windows 32bits được định nghĩa là hệ thống bộ nhớ ảo đòi hỏi phân trang dựa trên nền mô hình bộ nhớ phẳng 4GB bằng cách sử dụng sơ đồ địa chỉ hóa 32 bit.
Hệ thống yêu cầu phân trang (demand-paged) điều khiển việc truy xuất vào bộ nhớ chính và việc thực thi quá trình , dựa trên các phần mềm yêu cầu cho hệ điều hành mà phần mềm đang xử lý đặt ra. Hệ điều hành cũng giám sát các tài nguyên hệ thống, xác định quá trình nào đang yêu cầu bộ nhớ và cung cấp một vài cơ chế để đáp ứng các yêu cầu đó.
Bộ nhớ ảo là không gian bao gồm cả bộ nhớ vật lý liên kết với hệ thống lưu trữ trên đĩa cứng nhằm làm cho việc thi hành của các quá trình có đủ vùng nhớ để thực thi các chỉ thị phầm mềm.
Mô hình bộ nhớ phẳng tuyến tính cho phép đánh địa chỉ bắt đầu tại một vài vị trí nào đó, 0 hay 0000h và tiếp tục cho đến giới hạn lớn nhất, 4G hay FFFF:FFFFh bằng cách dùng sơ đồ đánh địa chỉ tăng dần. Sơ đồ địa chỉ hóa này chỉ được hỗ trợ bởi phần cứng của hệ thống 386 hoặc cao hơn.
Mô hình lập trình 386:
Các thanh ghi và đường dẫn dữ liệu 32 bit của hệ thống 386 (và cao hơn) cho phép 4GB không gian địa chỉ vật lý. Không gian bộ nhớ ảo của chế độ bảo vệ 30386 gồm có 16383 tuyến tính cho mỗi bộ nhớ 4GB. Việc biểu hiện bộ nhớ tuyến tính 4GB được gọi là mô hình bộ nhớ phẳng (flat memory model). Mỗi thanh ghi đơn có thể được coi như một con trỏ chỉ vào không gian địa chỉ 4GB này. Các thanh ghi trong 80386 có giá trị 32 bit, gồm 5 nhóm chính:
Nhóm thanh ghi đa dụng (general purpose register): dùng di chuyển dữ liệu ra vài bộ vi xử lý, kiểm tra và lập các cờ trạng thái.
Nhóm các thanh ghi gỡ rối (debuging register): cho phép người lập trình thiết lập một vài địa chỉ ngắt (breakpoint address) trong quá trình để theo dõi, gỡ lỗi cho chương trình.
Nhóm các thanh ghi trạng thái và điều khiển (status and control register): cung cấp các cờ trạng thái chỉ ra kết quả của các phép toán và được dùng để thay đổi các bước thực thi của chương trình dựa vào kết quả kiểm tra cờ. Các thanh ghi cờ trạng thái được bộ quản lý bộ nhớ ảo VMM sử dụng rộng rãi để quản lý bộ nhớ.
EIP là thanh ghi lệnh mở rộng (extended instruction register): chỉ ra địa chỉ của lệnh tiếp theo sẽ được thi hành.
Nhóm các thanh ghi điều khiển (control register): được hệ điều hành dùng điều khiển việc thực thi chương trình và được dùng bởi VMM để đánh địa chỉ cho bộ nhớ ảo, hỗ trợ đặc điểm tổ chức bộ nhớ theo trang của 386.
Các thanh ghi phân đoạn (segment register): duy trì sự tương thích với hệ thống 80286 và cung cấp địa chỉ phân đoạn khi 386 chạy trong chế độ thực hoặc chế độ chuẩn.
Địa chỉ hóa bộ nhớ ảo: Windows 32bits dùng sơ đồ địa chỉ phân trang làm cho bộ nhớ vật lý dường như rộng thêm hơn.
Thư mục trang (page directory): là một bảng chứa đựng địa chỉ của 1024 bảng trang (page table), mỗi địa chỉ rộng 32 bit nên kích thước của thư mục trang là 4096 bytes.
Bảng trang (page table): bao gồm là các điểm nhập, mỗi điểm nhập là sự kết hợp của địa chỉ vật lý và các cờ trạng thái của bộ nhớ vật lý. Sự kết hợp giữa thư mục trang và một bảng trang đơn độc sẽ đánh địa chỉ cho 4MB bộ nhớ. Vì vậy nếu RAM được thêm vào thì đòi hỏi cũng phải thêm bảng trang cho mỗi 4MB. Các địa chỉ bảng trang tuần tự được lưu giữ trong thư mục trang cho đến tối đa 1024 địa chỉ. Cách đánh địa chỉ trang như trên là lý do giải thích tại sao bộ nhớ tối thiểu cho Windows 32bits là 4MB. Mỗi quá trình trong Windows 32bits có một tập các địa chỉ bảng trang được gán cho nó. Mỗi địa chỉ này bao gồm phần 20 bit cao là một địa chỉ vật lý và phần 12 bit thấp là các cờ trạng thái. Các cờ này cung cấp thông tin cần thiết cho thành phần Kernel của Windows và chương trình người sử dụng.
Khung trang (page frame): mỗi khung trang được đánh địa chỉ duy nhất bởi một điểm nhập trong bảng trang. Phần 12 bit thấp của địa chỉ ảo 32 bit này đặc tả cho 1 byte duy nhất của bộ nhớ. Việc sử dụng 12 bit này sẽ đánh địa chỉ toàn bộ 4096 byte của khung trang và như vậy khung trang sẽ chỉ vào các địa chỉ RAM vật lý.
Như vậy một địa chỉ ảo 32 bit được chia làm 3 phần:
10 bit cao (22 - 31) chỉ ra bảng trang được chọn trong thư mục trang
10 bit tiếp theo (12 - 21) chỉ ra địa chỉ của khung trang thuộc bảng trang
12 bit thấp (0 - 11) đặc tả cho địa chỉ byte vật lý bên trong ranh giới 4K của trang
Không gian bộ nhớ ảo của trình ứng dụng:
Trong Windows 32bits, mỗi quá trình có một không gian địa chỉ 4GB riêng của nó. Các nhánh (thread) thuộc quá trình chỉ có thể truy xuất đến không gian nhớ thuộc về quá trình đó mà thôi. Không gian địa chỉ của tất cả các quá trình khác đều không thể truy xuất đối với nhánh đang chạy. Tuy nhiên riêng trong Windows 32bits thì không hoàn toàn trọn vẹn như vậy, vùng nhớ thuộc về hệ điều hành không được che giấu đối với nhánh đang chạy do vậy rất có khả năng nhánh đang chạy vì một sự cố nào đó sẽ truy xuất vào vùng dữ liệu của hệ điều hành và làm hỏng hệ thống.
Không gian địa chỉ của mỗi quá trình được phân thành các vùng như sau:
Vùng địa chỉ từ 0x00000000 đến 0x003FFFFF:
Đây là vùng nhớ kích thước 4MB ở phần đáy của không gian địa chỉ, Windows 32bits dùng để đảm bảo tính tương thích với MS-DOS và Windows 16 bit. Các ứng dụng 32 bit không nên đọc ghi vào vùng này. Về mặt lý thuyết thì CPU sẽ tạo ra lỗi truy xuất (access violation) nếu một nhánh nào đó của quá trình chạm vào vùng nhớ này, tuy nhiên vì lý do kỹ thuậ thì thực tế Microsoft không thể bảo vệ toàn bộ vùng nhớ này mà chỉ có thể bảo vệ vùng 4KB thấp nhất. Vì thế nếu một nhánh nào đó của quá trình cố gắng đọc ghi vào vùng nhớ có địa chỉ từ 0x00000000 đến 0x00000FFF thì CPU sẽ phát hiện và báo lỗi truy xuất. Việc bảo vệ vùng 4KB này đặc biệt hữu ích cho việc phát hiện các phép gán con trỏ rỗng.
Vùng địa chỉ từ 0x00040000 đến 0x7FFFFFFF:
Phần không gian 2.143.289.344 (= 2GB – 4KB) là nơi thường trú của không gian địa chỉ riêng (không chia sẻ) của quá trình. Một quá trình Win32 không thể đọc/ghi hoặc bằng bất kỳ cách nào truy xuất truy xuất dữ liệu của quá trình khác đang thường trú trên vùng này. Đối với tất cả các ứng dụng Win32, vùng này là nơi mà phần chính yếu của dữ liệu quá trình đang cất giữ.
Vùng địa chỉ từ 0x80000000 đến 0xBFFFFFFF:
Vùng 1GB này là nơi hệ thống cất giữ dữ liệu dùng chia sẽ giữa tất cả các quá trình Win32 chẳng hạn như các thư viện liên kết động hệ thống, kernel32.dll, user32.dll, gdi32.dll, advapi32.dll đều được nạp vào vùng không gian địa chỉ này. Chính điều này làm cho 4 thư viện hệ thống trở nên dễ dàng khả dụng đối với toàn bộ các quá trình Win32 một cách đồng thời. Hệ thống cũng ánh xạ toàn bộ các tập tin ánh xạ bộ nhớ (memory-mapped file) vào vùng này.
Vùng địa chỉ từ 0xC0000000 đến 0xFFFFFFFF:
Vùng 1GB này là nơi mã lệnh của hệ điều hành được định vị, bao gồm các trình điều khiển thiết bị ảo của hệ thống (VxD), mã lệnh quản lý bộ nhớ ở mức thấp, mã lệnh tập tin hệ thống. Cũng giống như vùng nhớ trước, toàn bộ mã lệnh trong vùng này được chia sẽ cho tất cả quá trình Win32. Tuy nhiên dữ liệu trong vùng này lại không được bảo vệ, bất kỳ một ứng dụng Win32 nào cũng có thể đọc/ghi vào vùng này và làm hỏng hệ thống.
Như vậy thì ý tưởng cơ bản cho việc thực hiện kỹ thuật override trong Windows 32 là cũng nhảy tới địa chỉ của hàm override tương ứng mỗi khi hàm API nào đó được gọi. Tuy nhiên, đối với Windows 32bits thì mỗi quá trình trong hệ thống đều được thực thi trong một không gian địa chỉ riêng rẽ. Nên muốn can thiệp vào quá trình gọi hàm của ứng dụng thì chúng ta phải bằng mọi cách thâm nhập vào không gian địa chỉ của ứng dụng, thì lúc đó chúng ta mới có thể điều khiển được quá trình gọi hàm API. Nhưng ở Windows 16 bit thì các hàm dùng để thay đổi thuộc tính các trang nhớ chứa mã hàm API thì nay ở trong Windows 32 bit không còn được hỗ trợ nữa. Như vậy làm theo cách như ở Windows 16 bit là không khả thi, vấn đề đặt ra là phải tìm cách thay đổi thuộc tính các trang nhớ đang chứa mã hàm API nguyên thủy.
Chúng tôi đã cố gắng nghiên cứu công việc này bằng các phương pháp được giới thiệu trong chương 16: Breaking Through Process Boundary Walls của cuốn Advance Windows – The Developer’s Guide to the Win32 API for Windows NT 3.5 and Windows 95 và tìm cách thực hiện nhưng chưa đạt được kết quả khả quan.
Do hạn chế về thời gian cũng như tài liệu tham khảo về các kỹ thuật này rất ít nên việc nghiên cứu để tìm ra cách giải quyết vấn đề sử dụng kỹ thuật override trong Windows 32bits chưa đi đến kết quả nên chúng tôi buộc phải chọn kỹ thuật override trong Windows 16bits để overrride các hàm xuất văn bản có sẵn để áp dụng vào chương trình của mình.
V – Hiện thực kỹ thuật override trên Windows 16bits:
Phương pháp mà chúng tôi chọn để áp dụng vào chương trình là ở dạng front-end processing tức là 5 bytes lệnh đầu tiên của đoạn mã lệnh hàm API sẽ được ghi đè bằng 5 bytes của lệnh JMP address trong đó byte thứ nhất là mã hợp ngữ của lệnh CALL, 4 byte kế tiếp là offset và segment tương ứng của đoạn mã lệnh hàm override.
Trình tự hiện thực bao gồm các bước sau:
1 - Xác định địa chỉ bộ nhớ nơi đoạn mã lệnh override thường trú:
Thường chúng được tập hợp dưới dạng các tập tin .DLL, .EXE của developer. Có 2 hàm để lấy địa chỉ logic trong bộ nhớ của bất kỳ hàm API nào: GetProcAddress và MakeProcInstance.
2 - Xác định địa chỉ bộ nhớ nơi bắt đầu đoạn mã tương ứng của hàm API cần override:
Đây cũng chính là điểm nhập của các hàm trong thư viện liên kết động đã được nạp vào bộ nhớ. Các thư viện này là thành phần cơ bản của Windows và được nạp vào bộ nhớ khi Windows khởi động. Tại địa chỉ bộ nhớ của hàm API có được ta có thể tạo một lệnh nhảy từ đây đến địa chỉ đoạn mã lệnh override. Nhưng Windows chỉ cho phép ghi lên data segment chứ không cho phép ghi lên code segment. Vì vậy ta phải có bước trung gian:
3 - Thay đổi thuộc tính của segment chứa mã hàm API trong Windows:
Bằng cách dùng hàm PrestoChangoSelector để có thể thay đổi thuộc tính segment theo 2 chiều: từ code sang data hoặc từ data sang code.
4 - Ghi mã lệnh nhảy vào địa chỉ bắt đầu đoạn mã hàm API:
Dùng lệnh nhảy không điều kiện JMP thì lúc đó stack của ứng dụng sẽ không đổi, đỉnh stack vẫn là địa chỉ trở về ứng dụng sau lệnh gọi hàm API, do vậy khi gặp lệnh return trong thân hàm override thì địa chỉ trở về là địa chỉ lệnh kế tiếp sau lệnh gọi hàm API trong ứng dụng. Như vậy để làm điều này thì chúng ta ghi đè 5 bytes đầu tiên tại địa chỉ bắt hàm API với dội dung là mã hợp ngữ của lệnh JMP address trong đó byte đầu tiên là mã lệnh JMP, có giá trị là 0EAh, 4 byte kế tiếp là địa chỉ logic dạng kiến trúc đoạn offset (2 byte)-segment (2 byte) nơi bắt đầu đoạn mã lệnh override của developer.
5 - Phục hồi 5 bytes nguyên thủy mã lệnh đầu tiên của hàm API:
- Để gỡ bỏ override, trả lại hàm API như cũ.
- Giải thuật thực hiện nói chung giống hệt như việc cài đặt override, chỉ khác là thay vì ghi mã lệnh nhảy và địa chỉ thì bây giờ ghi 5 bytes nguyên thủy của hàm API.
- Năm bytes nguyên thủy của hàm API là hằng số, nên có thể dùng m
Các file đính kèm theo tài liệu này:
- LV0875.doc