Chú ý: Để hiểu về vấn đề mình định nói đến bạn cần biết thế nào là các hàm API và có một chút kiến thức về ASm.
Kỹ thuật Hook API
Hook API là kỹ thuật dùng để chặn các lời gọi hàm API trong windows và chuyển hướng sang một hàm khác do người dùng xây dựng. Các hàm thay thế này thường sử dụng hoặc làm thay đổi các tham số truyền vào (hoặc kết quả trả về) để phục vụ cho một mục đích nào đó, trước khi trả lại cho hàm API ban đầu, để thực thi tiếp tác vụ của hệ thống.
Đây là ý tưởng mà các loại virus, trojan, rootkit ... thường sử dụng để ẩn thân đối với các chương trình kiểm tra file, tiến trình hay kết nối mạng. Ví dụ: khi ta hook 2 hàm FindFirstFileA và FindNextFileA, chúng ta sẽ kiểm tra và loại bỏ tên của chương trình cần ẩn ra khỏi danh sách trả về, do đó khi thực hiện việc tìm kiếm bằng lệnh dir trên DOS hoặc search trên Windows sẽ không thể thấy file virus.
Có 2 phương pháp hook API cơ bản là:
1. Import/Export Table Modification
Đây là kỹ thuật hook API bằng cách thay đổi trực tiếp các bảng Import/Export Tables của tiến trình cần hook bao gồm tất cả các module của nó (Dll). Mỗi tiến trình (process) và các module của nó (Dll) đều có một bảng Import Address Table (IAT) chứa địa chỉ các hàm API mà chúng sử dụng. Địa chỉ này được sử dụng khi tiến trình thực hiện lời gọi hàm API. Vì vậy bằng cách thay đổi giá trị của các địa chỉ này người ta có thể chuyển hướng một lời gọi hàm API thông thường sang một hàm khác.
Tuy nhiên một số chương trình gọi các hàm API thông qua địa chỉ có được bằng cách sử dụng hàm lấy địa chỉ GetProcAddress chứ không phải từ bảng IAT. Do đó chúng ta cần phải chặn thêm hàm GetProcAddress để thay đổi kết quả trả về nếu đó là yêu cầu lấy địa chỉ của một hàm API mà chúng ta cần hook.
Ưu nhược điểm:
Phương pháp này có ưu điểm là chỉ cần hook 1 lần, không gây xung đột và cài đặt đơn giản. Nhược điểm của kỹ thuật này đó là không phải lúc nào cũng thực hiện được. Nếu bảng IAT nằm trong phân đoạn được bảo vệ của tiến trình thì ta sẽ không thể thay đổi.
Do đó người ta thường phải sử dụng một kỹ thuật khác để hook các hàm API đó là kỹ thuật thay đổi trực tiếp trên các hàm API cần hook.
Nói chung cách này không được hay cho lắm, cho nên mình sẽ không hướng dẫn viết hook APi bằng cách này mà sẽ bằng cách thứ 2
2. Chèn lệnh JMP vào đầu hàm API
Để hook hàm API ta có thể thay đổi trực tiếp trên hàm đó, bằng phương pháp trèn lệnh JMP ta có thể làm cho chương trình chạy hàm của ta trước khi nó chạy hàm Window API.
Chẳng hạn ta có 1 hàm
WinExists ( "title" [, "text"] )
hàm này trong autoIT tương đương với hàm FindWindowA trong API.
Giá trị trả về là HWND của window ta cần tìm. Nếu không tìm thầy giá trị của nó là 0
Lệnh WinExists ( "title" [, "text"] ) tương đương với đoạn code sau:
Push title
Push text
Call 7E42E591 ( đây là địa chỉ của ham FindWindowA)
Và trong đó hàm findwindowA (địa chỉ 7E42E591) sẽ có code như sau
7E42E591 > 8BFF MOV EDI,EDI
7E42E593 /. 55 PUSH EBP
7E42E594 |. 8BEC MOV EBP,ESP
7E42E596 |. 33C0 XOR EAX,EAX
7E42E598 |. 50 PUSH EAX
7E42E599 |. FF75 0C PUSH DWORD PTR SS:[EBP+C]
7E42E59C |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
7E42E59F |. 50 PUSH EAX
7E42E5A0 |. 50 PUSH EAX
7E42E5A1 |. E8 4CFFFFFF CALL USER32.7E42E4F2
7E42E5A6 |. 5D POP EBP
7E42E5A7 \. C2 0800 RETN 8
Giờ nếu ta muốn hàm FindWindowA không bao giờ tìm được cái 1 cái cửa sổ nào đó, ta sẽ dùng cách hook API vào hàm này bằng cách cho nó nhảy vào hàm ta tạo ra:
7E42E591 > - E9 C04ECF81 JMP 00123456 ;---> lệnh này sẽ khiến cho chương trình nhảy vào hàm của ta có địa chỉ 123456 sau khi chạy xong hàm của ta ta sẽ cho chương quay trở lại ham API )
7E42E596 |. 33C0 XOR EAX,EAX
7E42E598 |. 50 PUSH EAX
7E42E599 |. FF75 0C PUSH DWORD PTR SS:[EBP+C]
7E42E59C |. FF75 08 PUSH DWORD PTR SS:[EBP+8]
7E42E59F |. 50 PUSH EAX
7E42E5A0 |. 50 PUSH EAX
7E42E5A1 |. E8 4CFFFFFF CALL USER32.7E42E4F2
7E42E5A6 |. 5D POP EBP
7E42E5A7 \. C2 0800 RETN 8
Rõ ràng khi ta chèn lệnh JMP vào đầu hàm API thì hàm API đó sẽ mất đi 5 byte đầu( do lệnh JMp chiếm 5 byte nên nó sẽ chèn vào 5 byte nguyên gốc của ham API là ở đây là: 5 byte:
Hình ảnh
8F FF 55 8B EC
Sẽ bị thay thế bằng 5 byte:
E9 C0 4E CF 81
Như vậy nếu ta không trả lại 5 byte đó chương trình sẽ bị crash.
Vậy phải làm thế nào:
Ta có 2 cách:
Cách 1:
Hình ảnh
Cách 2:
Hình ảnh
Nói sơ qua về cách 1 nhé:
Cách một có thể giai thích như sau:
Đâu tiên ta gán lệnh JMP đên hàm ta tạo ra vào ham API, hàm ta tạo ra sẽ phục hồi lại 5 byte bị mất của ham APi, rồi CAll hàm API.
Như vậy có một vấn để xảy ra là khi tiến trình mà ta hook hàm API có nhiều luồng xử lý cùng lúc và các luồng này liên tiếp gọi hàm API thì rất có khả năng xảy ra xung đột khi thay thế và trả lại 5 byte đầu của hàm API.
Nói chung cái cách đó không hay và ít khi được dùng.
Cách 2:
Cũng gán lệnh JMP vào hàm API, nhưng thay vì phục hồi 5 byte đầu ta sẽ tạo một cái hàm sẽ chứa các câu lệnh ASM bị lệnh JMP chèn mất
Ví dụ như sau:
mov edi, edi
push ebp
mov ebp, esp
xor ecx, ecx
Ta sẽ chèn lệnh jmp vào đầu
07E34550 JMP bride
07E34555 xor ecx, ecx
Hàm Bride sé có dạng như sau:
mov edi, edi
push ebp
mov ebp, esp
jmp 07E34555
Đó là lý thuyết về hook API. Đó là một kĩ thuật rất khó, hãy có gắng đọc để hiểu, bạn có thể search google để tìm hiểu thêm hoạc vào đây http://www.codeproject.com/KB/system...ok_engine.aspx
Ở phần 2 mình sẽ chỉ các bạn cách viết code hook API
Nguồn : Của mod vietnam dịch từ bài hook api trong codeproject
Không có nhận xét nào:
Đăng nhận xét