Tải bản đầy đủ (.pdf) (25 trang)

Các chương trình quản lý phòng máy hiện nay ở Việt Nam - 4 pdf

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 (802.33 KB, 25 trang )



76





Hình 2-47 Màn hình Server – WorkStation
2.2.7.2.2 Tab Service:


77

Hình 2-48 Màn hình Server – Service
2.2.7.2.3 Tab Administration:


Hình 2-49 Màn hình Server – Keylock





78


Hình 2-50 Màn hình Server – Keylog


Hình 2-51 Màn hình Server – Message






79

Hình 2-52 Màn hình Server – Apllication



Hình 2-53 Màn hình Server – Service




80

Hình 2-54 Màn hình Server – Snapshot

2.3 Cài đặt và thử nghiệm:
2.3.1 Cài đặt:
Ứng dụng Server và CafeClient được phát triển sử dụng các công cụ và môi
trường sau:
+ Công cụ phân tích và thiết kế: Rational Rose 2003
+ Môi trường cài đặt ứng dụng: Windows XP Professional
+ Môi trường lập trình: Microsoft Visual Studio 6.0
2.3.2 Thử nghiệm:
Chương trình được cài đặt thử nghiệm trên phòng máy của trung tâm mạng
Máy Tính Nhất Nghệ - đường Bà Huyện Thanh Quan - với kết quả như sau:.





STT Tính năng thử nghiệm Đánh giá
1 Kết nối Tốt
2
Tính cước và các dịch vụ liên
quan Tốt
3 Quản trị từ xa Tốt
4 Chụp màn hình tĩnh Tốt
5 Chụp màn hình động Tốt
6 Policy
Tùy thuộc vào thiết lập máy phía
Client


81
Chương 3 Các kỹ thuật lập trình
3.1 Kỹ thuật lập trình sự kiện và hook
Trong quá trình thực hiện phần mềm, có một yêu cầu quản trị hệ thống là
người quản trị cần biết lúc này người dùng đang gõ nội dung gì trên bàn phím hoặc
anh ta có nhu cầu khóa tạm thời bàn phím hay một số phím nhất định. Các nhu cầu
đó dẫn đến tình huống cần một cơ chế quản lý và kiểm soát bàn phím. Trong hệ
thống Windows, có một cơ chế đáp ứng như thế : cơ chế hook.
3.1.1 S
ự kiện và thông điệp trên HĐH Windows
Trước hết, ta phải hiểu thêm về cơ chế thông điệp của hệ điều hành
Windows. Đây là cơ chế cho phép các ứng dụng phân loại, lưu trữ, đáp lại tương tác
với người dùng cũng như là tương tác lẫn nhau.
* Hàng đợi thông điệp :


Để lưu trữ, phân loại, tương tác… Hệ điều hành Windows xây dựng hàng
đợi thông điệp. Hai loại hàng đợi thông điệp dùng cho mục đích này là:
o Hàng đợi hệ thống (System queue).
o Hàng đợi ứng dụng (Application queue).
Windows có các trình điều khiển thiết bị (Drivers) chịu trách nhiệm cho các
dịch vụ ngắt từ thiết bị phần cứng mouse và keyboard. Tại mỗi thời điể
m ngắt phát
sinh, các Driver này gọi một điểm vào (hàm) đặc biệt trong USER.EXE để chỉ ra
rằng một sự kiện vừa xảy ra. Các sự kiện mouse, bàn phím khi xảy ra đều trước hết
được lưu vào hàng đợi hệ thống. Mọi tiến trình trong hệ thống đều chia sẻ hàng đợi.
Hàng đợi hệ thống chỉ làm một nhiệm vụ duy nhất là ghi nhận các sự kiện mouse,
bàn phím (nhấn, rê mouse, nhấn bàn phím…) khi có.



82

Hình 3-1 Hàng đợi ứng dụng
Khi một tiến trình được khởi tạo, một hàng đợi đại diện cho nó được tạo ra,
hàng đợi này (đôi khi được gọi là hàng đợi tác vụ) được dùng để chứa những thông
điệp sẽ được gởi cho các cửa sổ của ứng dụng. Những thông điệp này là những
thông điệp được gởi một cách tường minh bằng một trong hai hàm sau :
o PostMessage
o
PostAppMessage
Ứng dụng có thể dùng hai hàm là GetMessage và PeekMessage do
Windows cung cấp để khảo sát hàng đợi của mình. Hai hàm này cho phép ứng dụng
lấy một thông điệp ra khỏi hàng đợi để từ đó phân loại và có những hồi đáp thích
hợp với người dùng.

3.1.2 Hook là gì ?
Hook là một cơ chế xử lý thông điệp của hệ thống mà một ứng dụng có thể
cài đặt một đoạn l
ệnh (subroutine) để theo lưu thông thông điệp trên hệ thống và xử
lý một số dạng thông điệp nào đó trước khi các thông điệp đến được thủ tục ở cửa
sổ đích.
3.1.3 Đặc tính của hook:
Hook có xu hướng làm chậm hệ thống vì chúng gia tăng số lượng công việc
xử lý của hệ thống cho mỗi thông điệp. Chỉ nên cài đặt hook khi cần thiết, và tháo
bỏ ngay khi không dùng nữ
a.


83
3.1.4 Các khái niệm trong hook:
3.1.4.1 Hook chains:
Hệ thống hỗ trợ nhiều loại hook; mỗi dạng cung cấp khả năng truy cập đến
khía cạnh khác nhau của cơ chế xử lý thông điệp. Chẳng hạn, ứng dụng có thể dùng
WM_MOUSE hook để kiểm soát lưu thông thông điệp của các thông điệp về
mouse.
Hệ thống duy trì một hook chain (dãy các hook) riêng rẽ cho mỗi loại hook.
Một hook chain là một danh sách các con trỏ trỏ đến các hàm do ứng dụng
định
nghĩa, đặc biệt riêng gọi là các hook procedure (thủ tục hook). Khi một thông điệp
phát sinh mà liên quan đến một loại hook, hệ thống chuyền thông điệp cho mỗi
hook procedure tham chiếu từ hook chain, hết cái này đến cái khác. Hoạt động một
hook procedure thực hiện tùy thuộc vào loại hook quy định. Các hook procedure
cho một số loại hook chỉ có thể quan sát các thông điệp; số còn lại có thể chỉnh sửa
thông điệp hay chặn quá trình chuyền thông đ
iệp trong hook chain, ngăn thông điệp

đến được hook procedure kế tiếp hoặc cửa sổ đích.
3.1.4.2 Hook procedure
Để tận dụng khả năng của mỗi loại hook, hệ thống cung cấp một hook
procedure và sử dụng hàm SetWindowsHookEx
để cài đặt hook procedure vào
trong hook chain liên quan. Hook procedure phải theo công thức:
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);
Có thể đặt tên tùy ý, không cần phải đúng là HookProc cho hook procedure.
Tham số nCode là mã hook mà hook procedure dùng để quyết định thao tác
thực hiện. Giá trị mã hook tùy thuộc vào loại hook; mỗi loại lại có bộ mã hook
mang tính chất riêng của nó. Các giá trị của tham số wParam và lParam tùy thuộc


84
mã hook, nhưng chúng đặc biệt chứa thông tin về thông điệp được gởi hay chuyển
(post).
Hàm SetWindowsHookEx
luôn cài đặt một hook procedure ở đầu hook
chain. Khi một sự kiện xảy ra mà được quan sát bởi một loại hook, hệ thống sẽ gọi
thủ tục ở đầu hook chain liên quan đến hook. Mỗi hook procedure trong chain quyết
định có nên chuyển sự kiện sang thủ tục kế tiếp. Một hook procedure chuyển sự
kiện sang thủ tục kế bằng cách gọi CallNextHookEx
.
Chú ý các hook procedure cho một số loại hook chỉ có thể quan sát thông
điệp mà thôi. Hệ thống chuyển thông điệp cho mỗi hook procedure, mặc cho mỗi
thủ tục có gọi CallNextHookEx.


Một hook toàn cục (global hook) kiểm soát các thông điệp cho mọi tiểu trình
trên cùng desktop với tiểu trình gọi hook. Một hook riêng cho tiểu trình (thread-
specific hook) kiểm sóat các thông điệp cho chỉ riêng tiểu trình đó thôi. Một hook
procedure toàn cục có thể được gọi trong ngữ cảnh của bất kỳ ứng dụng trên cùng
desktop với tiểu trình gọi, vì vậy thủ tục được gọi phải ở trong một module thư mục
liên kết động (dynamic linked library DLL) riêng r
ẽ. Một hook procedure riêng cho
tiểu trình chỉ được gọi trong ngữ cảnh của tiểu trình liên quan thôi. Nếu ứng dụng
cài đặt hook procedure một trong những tiểu trình của nó, hook procedure có thể
trong cùng module với phần mã còn lại của ứng dụng hay trong một DLL. Nếu một
ứng dụng cài đặt hook procedure cho một tiểu trình của một ứng dụng khác, thủ tục
phải ở trong DLL.
3.1.4.3 Các loại hook
Mỗi loại hook cho phép ứng dụng quan sát các khía cạnh khác nhau của cơ
chế xử lý thông điệp của hệ thống. Các loại hook khả dụng là :
• WH_CALLWNDPROC và WH_CALLWNDPROCRET Hooks
• WH_CBT Hook
• WH_DEBUG Hook
• WH_FOREGROUNDIDLE Hook


85
• WH_GETMESSAGE Hook
• WH_JOURNALPLAYBACK Hook
• WH_JOURNALRECORD Hook
• WH_KEYBOARD_LL Hook
• WH_KEYBOARD Hook
• WH_MOUSE_LL Hook
• WH_MOUSE Hook

• WH_MSGFILTER và WH_SYSMSGFILTER Hooks
• WH_SHELL Hook
Trong các hook kể trên, ta chỉ cần chú ý ba hook dành cho xử lý sự kiện bàn
phím WH_GETMESSAGE, WH_KEYBOARD, WH_KEYBOARD_LL.
3.1.4.3.1
WH_GETMESSAGE Hook
Hook cho phép quan sát các thông điệp sẽ trả về bởi các hàm GetMessage

PeekMessage
, có thể dùng hook để quan sát các dữ liệu nhập từ mouse và bàn phím
và các loại thông điệp khác từ hàng đợi thông điệp.
3.1.4.3.2 WH_KEYBOARD_LL Hook
Cho phép kiểm soát các sự kiện nhập từ bàn phím sẽ được chuyển đi trong
hàng đợi thông điệp.
3.1.4.3.3 WH_KEYBOARD Hook
Cho phép kiểm soát dòng lưu thông các thông điệp WM_KEYDOWN,
WM_KEYUP sẽ trả bởi hàm GetMessage
hay PeekMessage. Hook cũng có thể
được dùng để kiểm soát các sự kiện nhập từ bàn phím sẽ được chuyển đi trong hàng
đợi thông điệp.
3.1.5 Tiếp cận vấn đề:
Như vậy, ta phải tạo một hook có khả năng chặn bắt các sự kiện bàn phím,
ghi nhận, cho phép hoặc hủy bỏ trước khi các thông điệp bàn phím đến được cửa sổ


86
đích. Trong các loại hook nêu trên, ta thấy các loại hook phù hợp là:
WH_GETMESSAGE, WH_KEYBOARD, WH_KEYBOARD_LL. Tuy nhiên, mục
tiêu đề ra là làm thế nào để kiểm soát bàn phím mà thôi, WH_GETMESSAGE kiểm
soát hết các thông điệp, đồng thời hạn chế lớn nhất là WH_GETMESSAGE không

có tính năng lọc bỏ thông điệp. Như vậy, ta chọn được hai hook WH_KEYBOARD,
WH_KEYBOARD_LL. Ta chọn WH_KEYBOARD vì dễ cài đặt hơn, tương thích với
nhiều phiên bản hệ điều hành Windows. Do chứ
c năng khóa bàn phím là chức năng
có nhiều kỹ thuật khá thú vị, nên quá trình cài đặt chức năng này sẽ được đề cập
trước.
3.1.5.1 Tinh chế 0:
Xây d•ng m•t •ng d•ng ••n gi•n cài ••t m•t hook
toàn c•c. Khi •ng d•ng ch•y, phím ‘e’ trên bàn phím s•
b• vô hi•u hóa (không gõ •••c n•a).
Cài đặt hook toàn cục, ta cần viết các hàm cài đặt, gở bỏ hook và hook
procedure trong một module riêng, gọi là DLL (thư viện liên kết động). Trước hết,
ta cần khảo sát các hàm cài đặt, gở bỏ hook do Windows cung cấp. Các hàM API
này được nêu rõ trong Phụ lục Các hàm API hữu ích sử dụng trong chương
trình gồm: SetWindowsHookEx (cài đặt hook), UnhookWindowsHookEx (gở bỏ
hook), CallNextHookEx (truyền cho hook kế). Các hàm API của Windows từ đây
trở đi khi được đề
cập đến nếu được sử dụng nhiều trong chương trình, sẽ được nêu
rõ trong Phụ lục Các hàm API hữu ích sử dụng trong chương trình.
Xây dựng hook procedure:
Đây là lúc thích hợp để đề cập việc xây dựng hàm quan trọng nhất, hook
procedure. Hook procedure là một callback function, tức là một hàm chỉ được gọi
bởi Windows mỗi khi có sự kiện ứng với hàm xảy ra
Các hook procedure đều có dạng sau:
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,


87

LPARAM lParam
);
Ta cần sử dụng WH_KEYBOARD nên ta sẽ khảo sát cụ thể hook
procedure cho WH_KEYBOARD:
LRESULT CALLBACK KeyboardProc(
int code,
WPARAM wParam,
LPARAM lParam
);
code : xác định cách thức hook procedure xử lý thông điệp, nó là một trong
hai giá trị sau :
HC_ACTION : Thông điệp đã được lấy ra khỏi hàng đợi thông điệp.
wParam và lParam chứa thông tin về thông điệp mà hook procedure nhận được.
HC_NOREMOVE : wParam và lParam mang thông tin của thông điệp, và
thông điệp vẫn còn trong hàng đợi (ứng dụng gọi PeekMessage với tùy chọn
PM_NOREMOVE).
Nếu code âm, hook procedure phải chuyển thông điệp đi b
ằng cách gọi hàm
CallNextHookEx và trả về kết quả nhận được.
wParam : chứa mã phím ảo của phím được nhấn.
lParam : cho biết số lần lặp lại, mã quét, cờ mở rộng, mã ngữ cảnh, cờ trạng
thái trước của phím, và cờ chuyển trạng thái:
0-15 cho biết số lần lặp phím, là số lần nhấn phím được tính khi người
dùng giữ phím.
16-23 cho biết mã quét.
25-28 dành riêng.
29
cho biết mã ngữ cảnh. Giá trị 1 nếu phím ALT được nhấn, 0 nếu ALT
nhả
30 cho biết trạng thái phím trước đó. Giá trị 1 nếu phím được nhấn trước

khi thông điệp được gởi, 0 nếu ngược lại.


88
31 cho biết trạng thái chuyển đổi. 0 nếu phím đang nhấn, 1 nếu phím
được thả.
Tới đây, ta đã vượt qua một lượng lớn kiến thức khá thú vị về cơ chế hook.
Đã đến lúc làm một việc gì đó cụ thể, ta cài đặt bài tóan nêu ở Tinh chế 0:
Xây dựng các hàm cài đặt gở bỏ: quy tắc viết hàm theo module DLL, cách
nạp một DLL vào bộ nhớ và thực thi, xem chi trong phần mã nguồ
n chương trình. Ở
đây, ta chỉ đề cập đến cách hàm hoạt động mà thôi.
Hàm cài đặt:
LRESULT __declspec(dllexport) InstallKeyHook()
Cài đặt một WH_KEYBOARD để xử lý thông điệp bàn phím và trả về
handle hook cài đặt thành công hoặc lỗi nếu thất bại.
Hàm gở bỏ:
LRESULT __declspec(dllexport) UninstallKeyHook()
Gở bỏ WH_KEYBOARD hook đã cài đặt, trả về mã thông báo kết quả.
Hook procedure :
LRESULT CALLBACK KeyboardProc(INT nCode
, WPARAM wParam,
LPARAM lParam)
Ta chỉ xử lý khi thông điệp được lấy ra khỏi hàng đợi và chỉ xử lý một thông
điệp WM_KEYDOWN mà thôi (khi lọc bỏ thông điệp WM_KEYDOWN thì thông
điệp WM_KEYUP sẽ không được phát sinh, xem chi tiết về thông điệp bàn phím
trong Phụ lục Sự kiện bàn phím). Hai thông điệp WM_SYSKEYDOWN và
WM_SYSKEYUP cũng tương tự như thế.
Thử nghiệm:
Chương trình chạy ho

ạt động tốt nhưng khi ta thay đổi nhỏ như sau: cố
truyền một biến cho DLL, biến này cho biết mã phím ảo của phím sẽ bị chặn, chẳng
hạn, ‘e’, và truyền cho DLL như sau:
SetX(‘e’); //SetX là hàm đặt biến trong DLL.
và trong DLL khai báo một biến toàn cục như sau:
WPARAM x;


89
thì chương trình sẽ mất tác dụng khi ứng dụng của ta mất focus (không phải
là cửa sổ đang kích họat). Điều này không chấp nhận được vì ứng dụng ta mong
muốn cần phải chặn bắt các sự kiện bàn phím khi người dùng đang sử dụng.

Hình 3-2 Tinh chế 0
3.1.5.2 Tinh chế 1:
Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c.
Khi •ng d•ng ch•y, tùy theo phím ng••i dùng gõ vào mà
•ng d•ng s• khóa phím •ó.
Để giải quyết vấn đề, ta cần phải tìm hiểu kỹ cơ chế hoạt động cũng như tải
nạp một module DLL vào bộ nhớ khi ứng dụng cần. Điều cốt lõi ta cần biết chính là
không gian địa chỉ. Khi một DLL toàn cục được thực thi, nó sẽ thực thi trong ngữ
cảnh của tiến trình mà có sự kiện nó cần hook đ
ang xảy ra. Vì đây là một DLL, nó
sẽ có một bản sao riêng rẽ của những dữ liệu cần dùng của nó (trong trường hợp ta
khảo sát, đó là biến toàn cục x) cho mỗi tiến trình. Vì vậy, mỗi lần hook procedure
được gọi, DLL sẽ nạp vào không gian địa chỉ của tiến trình cần hook, và một loạt
các dữ liệu mà DLL dùng sẽ được khởi tạo mới (chẳng hạn các biến toàn cục khai
báo ở mứ
c độ tập tin như biến x đã nêu trên). Vì vậy, ta phải làm một cách nào đó
mà các dữ liệu ta cần (biến x) có thể dùng cho mọi thể hiện của DLL. Điều này có

thể thực hiện được bằng cách sử dụng đọan không gian địa chỉ chia sẻ (shared
segment), xem thêm chi tiết về vấn đề này trong phần Phụ lục DLL – thư viện liên
kết động.


90
Khi đó, do các biến ta cần đều được đặt trong đoạn không gian địa chỉ chia
sẻ, các thể hiện của DLL được nạp trong mỗi tiến trình đều “hiểu” (đọc được giá trị
trong bản gốc DLL nạp do ứng dụng của ta đặt). Để khai báo một phân đoạn không
gian địa chỉ chia sẻ, ta làm như sau:
#pragma data_seg(“.VAN”)
//Các biến cần sử dụng chung
#pragma data_seg()
#pragma comment(linker, “/section:.VAN,rws”)
với “.VAN” là tên đặt gợi nhớ tùy ý cho phân
đoạn (nhưng không được dài
hơn 8 ký tự). #pragma comment ở trên đặt thêm một tùy chọn biên dịch cho các tập
tin biên dịch .OBJ.
Đến đây, mọi việc lại trở nên quá dễ dàng với phân đọan chia sẻ ta vừa tạo
ra. Ta chỉ việc tạo ra 255 biến trạng thái (kể cả các ký tự điều khiển và mở rộng, có
thể có tới 256 ký tự). Các biến này lưu trữ trạng thái của phím như sau:
#define
MAX_KEYS_LOCK 255
static BOOL g_bHook[MAX_KEYS_LOCK]
với FALSE cho biết phím chưa khóa
TRUE cho biết phím đã khóa
đặt mảng các biến vào trong phân đọan vừa tạo trên và chỉnh sửa lại hook
procedure KeyboardProc:
Thế là ta hoàn tất vấn đề chính. Việc còn lại chỉ đơn giản là thiết lập hàm ghi
giá trị biến trong DLL và gọi nó trong ứng dụng

Thử nghiệm tinh chế 1:
Chương trình hoạt động khá tốt nhưng ta v
ẫn chưa đề cập đến các phím chức
năng (ví tổ hợp Alt-Tab…). Thật vậy, chương trình hoàn toàn bất lực trước các
phím chức năng vì ta không thiết kế chức năng “nhập” các phím chức năng, mà cho
dù có, ta cũng không “bắt” được. Điều này không chấp nhận được vì ứng dụng ta
mong muốn cần phải chặn bắt các sự kiện bàn phím khi người dùng đang sử dụng.


91

Hình 3-3 Tinh chế 1
3.1.5.3 Tinh chế 2:
Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c.
Khi •ng d•ng ch•y, cho phép vô hi•u hóa b•t k• phím nào
trên bàn phím.
Để giải quyết vấn đề này, ta cần xem xét lại khả năng của hook
WH_KEYBOARD. Hook không có khả năng chặn bắt các tổ hợp phím như: Alt-
Tab… Vì vậy, ta đành phải sử dụng hook khả dĩ cuối cùng là hook
WH_KEYBOARD_LL. Tuy nhiên, hook là một hook mới có từ Windows
NT/2000/XP trở về sau. Đây là một hook rất mạnh nhưng cách dùng cũng như
tham số đầu vào khác rất nhiều so với WH_KEYBOARD. Do
đó, ta phải tinh chỉnh
lại hook procedure nếu không muốn thay đổi toàn bộ cài đặt từ trước.
Khảo sát hook procedure của WH_KEYBOARD_LL :
LRESULT CALLBACK LowLevelKeyboardProc(
int nCode,
WPARAM wParam,
LPARAM lParam
);

Ý nghĩa tham số:


92
[in]
nCode: xác định cách thức xử lý thông điệp. Nếu nCode âm, phải chuyển
thông điệp sang hook procedure kế, và trả về kết quả nhận được, chỉ có thể là giá
trị:
HC_ACTION wParam và lParam chứa thông tin về thông điệp bàn phím.
wParam: xác định loại thông điệp. Đó là: WM_KEYDOWN, WM_KEYUP,
WM_SYSKEYDOWN, và WM_SYSKEYUP.
lParam: trỏ đến cấu trúc KBDLLHOOKSTRUCT.
Cấu trúc KBDLLHOOKSTRUCT như sau:
typedef struct {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
Có ý nghĩa như trong Phụ lục Sự kiện bàn phím.
Ý nghĩa tham số:
[in]
vkCode : mã phím ảo từ 1-254.
scanCode: mã quét phần cứng.
flags: cờ phím mở rộng, cờ sự kiện thêm vào, mã ngữ cảnh, và cờ chuyển
đổi trạng thái. Ứng dụng dùng các giá trị sau để kiểm tra cờ nhấn phím
Value Purpose
LLKHF_EXTENDED Kiểm tra cờ mở rộng.
LLKHF_INJECTED Kiểm tra cờ thêm sự kiện.

LLKHF_ALTDOWN Kiểm tra mã ngữ cảnh.
LLKHF_UP Kiểm tra cờ chuyển trạng thái.


93
Bảng 3-1 Giá trị khảo sát phím mở rộng

0 cho biết phím có là phím mở rộng hay không, chẳng hạn như phím
chức năng hay phím bên bảng số (numpad). Giá trị 1 nếu đúng, 0 nếu
sai.
1-3 Dành riêng.
4 Cho biết sự kiện này có phải do được thêm vào không (chứ không
phải do từ bàn phím gõ). Giá trị 1 nếu đúng, 0 nếu sai.
5 Cho biết mã ngữ cảnh, phím alt có được nhấn hay không. Giá trị 1
nếu đúng,
0 nếu sai.
6 Dành riêng.
7 Cho biết trạng thái phím. Giá trị 0 nếu phím nhấn và một nếu phím
được thả.
time Cho biết tem thời gian của thông điệp.
dwExtraInfo Cho biết các thông tin đi kèm thêm với thông điệp.
So sánh với các tham số của WH_KEYBOARD, ta cần giả lập wParam,
lParam của WH_KEYBOARD từ wParam, lParam của WH_KEYBOARD_LL.
wParam: khá dễ dàng, wParam của WH_KEYBOARD chính là vkCode
trong cấu trúc KBDLLHOOKSTRUCT do lParam của WH_KEYBOARD_LL trỏ
đến.
lParam: phức tạp hơn một chút,
ở đây ta phải giả lập lại giá trị DWORD của
lParam trong WH_KEYBOARD từ cấu trúc KBDLLHOOKSTRUCT do lParam
của WH_KEYBOARD_LL trỏ đến. Hàm MakeFakelParam sẽ giúp ta làm điều này:

LPARAM MakeFakelParam(PKBDLLHOOKSTRUCT pKb)
Hàm có tác dụng chuyển đổi giá trị lParam trong cấu trúc
KBDLLHOOKSTRUCT sang giá trị lParam của WH_KEYBOARD.
Tuy thế, mọi việc vẫn chưa kết thúc. Rắc rối xảy ra khi ta nhấn phím ALT.
Phím ALT sẽ nhận biết được nếu ta nhấn phím mà không kèm theo một phím khác.


94
Phím sẽ không biết được nếu ta nhấn kèm với phím khác vì khi đó, driver bàn phím
sẽ thông dịch phím ALT thành mã ngữ cảnh. Vì vậy, đối với riêng tình huống này ta
phải xử lý riêng:
So sánh thêm mã ngữ cảnh:
if( (g_bHook[VK_LMENU]) || (g_bHook[VK_RMENU]) )
if(p->flags & LLKHF_ALTDOWN) // co nhan kem alt voi phim nay
return 1;
Như vậy bài tóan tinh chế 2 đã được giải quyết hoàn chỉnh.
chèn hình
Thử nghiệm:
Chương trình chạy tốt yêu cầu đề ra. Lưu ý rằng do tính chất là một hook cấp
thấp, nên vấn đề nhận biết số lần lặp lại phím khá phức tap. Ta có thể bỏ qua việc
này vì ứng dụng thực sự của ta không cần đến.Vấn đề còn lại là ghi nhận phím, mộ
t
keylogger đơn giản, ít phức tạp hơn nhiều.

Hình 3-4 Tinh chế 2
3.1.5.4 Tinh chế 3:
Xây d•ng m•t •ng d•ng cài ••t m•t hook toàn c•c.
Khi •ng d•ng ch•y, xu•t ra màn hình ký t• ng••i dùng gõ.
Ta cần lưu ý kỹ thuật lập trình truyền thông điệp chứa dữ liệu ký tự phím gõ
từ hook procedure đến cửa sổ xử lý. Điều này có thể thực hiện được khi lúc ban đầu



95
khởi tạo hook ta cần cho hook biết cần kiểm sóat bao nhiêu phím (cả bàn phím),
handle cửa sổ chính, loại thông điệp (ứng dụng ta không cần quan tâm nên ta chỉ
cần thông điệp WM_KEYDOWN), các loại cửa sổ cần kiểm sóat (mọi cửa sổ), các
phím kết hợp kèm theo (ta không quan tâm). Tất cả các thông tin trên được gọi là
một bộ kiểm sóat (entry). Hàm LogKeyboard sẽ giúp ta làm điều này:
LRESULT CKeyLogClient::LogKeyboard(HWND hWnd)
Hàm sẽ gọi hàm AddKeyEntry, là mộ
t hàm trong DLL. Hàm có tác dụng lưu
trữ các dữ liệu trên. Khi đó, cài đặt hook xong ta chỉ việc đợi kết quả gởi tới cửa sổ
xử lý. Dĩ nhiên, hook procedure cần sửa lại để thông báo cho cửa sổ cài đặt hook
biết có thông điệp mã phím cần xử lý (sử dụng hàm PostMessage gởi thông điệp tự
định nghĩa cho cửa sổ chính với handle cửa sổ chính nhận được từ hàm
LogKeyboard).
LRESULT CALLBACK
KeyboardProc(INT nCode, WPARAM wParam,
LPARAM lParam)
Thử nghiệm:
Như vậy, ta đã hoàn tất được mục tiêu đề ra ban đầu. Mặc dù chương trình
hoàn chỉnh phải bao gồm nhiều kỹ thuật lập trình thú vị khác, nó lại không nằm
trong phạm vi tìm hiểu mà mục tiêu ta cần. Chương trình hoàn chỉnh còn có thêm
khả năng sử dụng hook cho đồng thời tối đa 256 tiến trình và tối đa 1024 bộ
kiểm
sóat. Phần việc còn lại chỉ cần thay đổi một ít mã nguồn để tích hợp vài chương
trình chính.


96


Hình 3-5 Tinh chế 3
3.2 Xây dựng màn hình che:
Trong quá trình thực hiện phần mềm, có một yêu cầu cần thiết cho chương
trình quản lý phòng máy là cần phải ngăn chặn người dùng không dùng máy khi
chưa đăng ký với người quản trị để sử dụng. Một điều thực tế hiển nhiên là các máy
tính trong phòng máy phải luôn bật máy sẵn sàng. Vì vậy, ta cần xây dựng một màn
hình che trên màn hình để người dùng không thể tương tác với máy.
3.2.1 Phân tích sơ lược:
Ta nhận thấy rằng
để tương tác với máy tính, thông thường người dùng sẽ sử
dụng hai thiết bị tương tác là mouse và bàn phím. Ta không cần quan tâm về các
loại thiết bị tương tác khác vì thông thường các phòng máy chỉ cần hai thiết bị nêu


97
trên là đủ. Vì vậy, ta sẽ xem xét các tương tác của người dùng để sử dụng máy tính
bằng hai thiết bị trên.
Sau khi khảo sát, quy trình sử dụng máy thông thường sẽ là:
1. Bật máy lên
2. Nếu có icon chương trình cần chạy trên desktop, kích hoạt chương trình.
3. Nếu chương trình không có trên desktop, người dùng sẽ lục tìm trên máy
bằng nhiều cách khác nhau như :
a. Nhấn Start, dò trên All Programs.
b. Nhấn Start, chạy Run, mở gõ chươ
ng trình cần chạy.
c. Chạy My Computer, dò chương trình trong cây thư mục.
d. Mở Windows Explorer, dò chương trình trong cây thư mục.
e. …
4. Khi sử dụng xong chương trình, người dùng đóng chương trình lại.

5. Quay trở lại bước 2 Vòng lặp sẽ xảy ra cho đến khi người dùng sử dụng
xong máy tính.
6. Tắt máy tính.
Các bước 1 và 6 có thể được bỏ qua. Ta sẽ xem xét các bước từ 2 đến 6. Dễ
dàng nhậ
n thấy rằng mọi tương tác của người dùng thông thường đều phải
thông qua desktop. Nếu ta làm cách nào đó ngăn chặn việc tương tác của
người dùng trên desktop, ta sẽ đạt được mục tiêu đề ra. Từ đây, ta sẽ đưa ra các
khảo sát cụ thể cho mỗi thiết bị mouse và bàn phím.
3.2.1.1 Tương tác bằng mouse:
Đây là thiết bị chủ yếu người dùng sẽ sử dụng để tương tác với máy tính.
Phần lớn người dùng thông thường sẽ không biết sử dụng máy, hoặc sẽ rất khó khăn
khi sử dụng máy mà không có mouse. Do tính phổ thông và cần thiết như thế, người
dùng sẽ phụ thuộc rất nhiều vào mouse.
Vẫn theo ý tưởng đề ra ở trên, ta để ý rằng thực chất desktop chỉ là một cửa
sổ của Windows, trên đó, mọi ứng dụng sẽ được chạy (mọi cửa sổ ứng dụng được


98
mở trên desktop đều là cửa sổ con của nó). Nếu có một cửa sổ nào đó nằm chồng
lên trên desktop, và cửa sổ đó đang kích hoạt, thì người dùng sẽ tương tác với cửa
sổ đó chứ không thể tương tác với desktop. Để có thể tương tác trở lại với desktop,
người dùng phải click mouse trái lên trên desktop (trong trường hợp cửa sổ bình
thường), nhấn nút Minimise trên thanh tiêu đề của cửa s
ổ (trong trường hợp cửa sổ
bình thường hoặc đang phóng to hết cỡ). Điều gì sẽ xảy ra nếu người dùng không
còn những khả năng trên :
o không thể click chuột trái lên trên desktop vì cửa sổ đang được phóng to hết
cỡ (maximized), che mất cả desktop và cả thanh taskbar .
o không thể thu nhỏ cửa sổ lên trên thanh taskbar, phục hồi cửa sổ lại kích

thước thông thường, và tắt cửa sổ
đi vì cửa sổ không có thanh tiêu đề.
Đến đây, ta đã thấy rõ cách làm. Điều duy nhất cần làm bây giờ là :
o tạo một cửa sổ không có thanh tiêu đề.
o kích hoạt cửa sổ mỗi khi máy vừa khởi động xong.
o “căng” kích cở của cửa sổ sao cho vừa khít với desktop.
Để làm được điều này, ta sẽ sử dụng các kỹ thuật và hàm thông thường được
cung cấp sẵ
n bởi Windows mà ta sẽ đề cập kỹ ở phần cài đặt. Bây giờ, đã đến lúc đề
cập đến bàn phím.
3.2.1.2 Tương tác với bàn phím:
Đây là thiết bị quan trọng thứ hai sau mouse để người dùng tương tác với
desktop. Phần lớn người dùng thông thường chỉ sử dụng bàn phím nhiều khi họ sử
dụng máy tính là đánh văn bản. Trong phòng máy tính Café Internet, bàn phím
được dùng để chat, nhập thông tin người dùng trong lúc lướt web… Chỉ có một số
nhỏ người dùng am hiểu rõ và ghi nhớ các phím tắt do Windows gán để tương tác
với desktop. Chẳng hạn, xem bảng so sánh các thao tác bằng mouse và bàn phím
qua hai thao tác hay dùng là mở Control Panel và shutdown máy:
Bằng mouse Bằng bàn phím


99
1. Mở Control Panel
a. Nhấn Start

b. Chọn All Programs
c. Chọn Control Panel
1. Mở Control Panel
a. Nhấn Win key, hoặc Ctrl-Esc
b. Nhấn phím r, kích hoạt cửa sổ Run

c. Gõ “control” trong ô Open (không có dấu “”)
d. Nhấn Enter
2. Shutdown máy :
a. Nhấn Start
b. Chọn Turn off
Computer
c. Chọn tiếp Turn off
2. Shutdown máy:
a. Nhấn Win key, hoặc Ctrl-Esc.
b. Nhấn phím r, kích hoạt cửa sổ Run.
c. Gõ “shutdown /s /t 0” trong ô Open (không có
dấu “”)
d. Nhấn Enter
Bảng 3-2 So sánh tương tác giữa mouse và bàn phím
Tùy thuộc vào cấu hình các phiên bản Windows mà các bước thực hiện có thể khác
đôi chút, ở đây ta sử dụng WindowsXP chế độ taskbar là “Start menu”, chế độ log
off là “Using Welcome Screen”.)
Nhìn chung các thao tác bằng bàn phím khá phức tạp hơn bằng mouse, tựu
trung lại chỉ cần nhớ phím và tổ hợp phím thực thi, câu lệnh, và làm một việc duy
nhất là …gõ. Do vậy, ta chỉ cần làm một việc duy nhất là vô hiệu hóa toàn bộ phím
bấm trên bàn phím là xong mà ta sẽ đề c
ập kỹ ở phần cài đặt.
3.2.2 Cài đặt:
Ta sẽ thực hiện những bước đề ra như ở trong phần 1.2.1 Phân tích sơ lược
lần lượt cho mỗi thiết bị.
3.2.2.1 Tương tác với mouse:
Ta sẽ tạo một cửa sổ. Tuy nhiên, cửa sổ theo dạng tài liệu (document) như
WinWord, Windows Explorer… không phù hợp cho mục tiêu. Cái ta cần sẽ là một
cửa sổ dạng hộp thoại (dialog), vì ta về sau có thể cần chèn hình ảnh giới thiệu. Vả
lại, ta cần một cửa sổ càng đơn giản càng tốt (ít cấu hình sẵn), hỗ trợ thiết kế trực



100
quan… thì trong Microsoft Visual Studio 6.0 viết chương trình bằng MFC, loại
project theo Dialog-based là thích hợp nhất.
Sau khi tạo một hộp thoại xong, ta cần cho cửa sổ “nổi” lên trên tất cả cửa sổ
khác kể cả desktop và thanh taskbar và “căng” kích cỡ chiếm hết cả màn hình. Hàm
API SetWindowPos sẽ giúp ta điều này.
Tuy thế, ta sẽ không gọi trực tiếp hàm API SetWindowPos mà gọi thông qua
phương thức của CWnd, lớp cha của lớp cử
a sổ thoại, SetWindowPos:
Phương thức chỉ khác hàm API ở chỗ chỉ có 6 tham số ứng lần lượt với 6
tham số cuối của hàm API. Phương thức sẽ thực thi bằng cách gọi lại hàm API và
thêm tham số đầu tiên của hàm API băng handle cửa sổ có sẵn cửa sổ lớp hộp thoại
m_hWnd.
Đến đây, có một vấn đề nhỏ cần giải quyết là lấy được kích th
ước của
desktop, hay nói cách khác là độ phân giải của màn hình. Ta không thể lấy cố định
kích thước, ví dụ là 800x600, vì mỗi màn hình sẽ được người dùng sẽ thay đổi độ
phân giải cho phù hợp với mắt nhìn. Do vậy, có hai cách giải quyết :
a. Đọc trực tiếp các giá trị độ dài và độ rộng của màn hình bằng hàm API
GetSystemMetrics:
Áp dụng hàm trong chương trình như sau:
int xScrn = ::GetSystemMetrics(SM_CXSCREEN);
int yScrn = ::GetSystemMetrics(SM_CYSCREEN);
SetWindowPos(&wndTopMost, 0, 0, xScrn, yScrn,
SWP_SHOWWINDOW);
Đọan mã trên đặt trong phương thức khởi tạo của cửa sổ hộp thoại, tham số
&wndTopMost nhằm đặt cửa sổ vào dãy thứ tự các cửa sổ dạng “nổi trội”, các tham
số sau có ý nghĩa là dời cửa sổ về góc trên bên phải màn hình, độ rộng và dài bằng

độ phân giải màn hình, kích hoạt và hiện cửa sổ.
b. Đọc các giá trị độ rộng và dài từ hai hàm API CreateDC,
GetDeviceCaps.
Dùng cách này có tiện lợi khi hệ thống có nhiều màn hình hiển
thị:

×