là dự án này để xây dựng một "khuôn khổ" đó (?) sẽ cho phép người khác móc các chức năng khác nhau trong các tệp nhị phân khác nhau? Hay chỉ là bạn cần phải móc chương trình cụ thể này mà bạn có?
Trước tiên, giả sử bạn muốn điều thứ hai, bạn chỉ có một hàm trong một tệp nhị phân mà bạn muốn móc, lập trình và đáng tin cậy. Vấn đề chính khi thực hiện điều này là việc thực hiện điều này một cách đáng tin cậy là một trò chơi rất khó khăn, nhưng nếu bạn sẵn sàng thực hiện một số thỏa hiệp, thì nó chắc chắn có thể thực hiện được. Ngoài ra chúng ta hãy giả định đây là điều x86.
Nếu bạn muốn móc một hàm, có một số tùy chọn cách thực hiện. Điều gì Detours là vá nội tuyến. Họ có một cái nhìn tổng quan tốt đẹp về cách nó hoạt động trong một Research PDF document. Ý tưởng cơ bản là bạn có một hàm, ví dụ:
00E32BCE /$ 8BFF MOV EDI,EDI
00E32BD0 |. 55 PUSH EBP
00E32BD1 |. 8BEC MOV EBP,ESP
00E32BD3 |. 83EC 10 SUB ESP,10
00E32BD6 |. A1 9849E300 MOV EAX,DWORD PTR DS:[E34998]
...
...
Bây giờ bạn thay thế đầu của hàm với một CALL hoặc JMP để chức năng của bạn và lưu các byte gốc mà bạn ghi đè lên với miếng vá ở đâu đó:
00E32BCE /$ E9 XXXXXXXX JMP MyHook
00E32BD3 |. 83EC 10 SUB ESP,10
00E32BD6 |. A1 9849E300 MOV EAX,DWORD PTR DS:[E34998]
(Lưu ý rằng tôi ghi đè lên 5 byte .) Bây giờ chức năng của bạn được gọi với cùng các tham số và quy ước gọi tương tự như hàm ban đầu.Nếu chức năng của bạn muốn gọi bản gốc (nhưng nó không phải), bạn tạo "tấm bạt lò xo", 1) chạy các lệnh gốc đã được ghi đè 2) jmps đến phần còn lại của hàm gốc:
Trampoline:
MOV EDI,EDI
PUSH EBP
MOV EBP,ESP
JMP 00E32BD3
Và đó là nó, bạn chỉ cần xây dựng chức năng trampoline trong thời gian chạy bằng cách phát ra các hướng dẫn của bộ xử lý. Phần khó của quá trình này là làm cho nó hoạt động đáng tin cậy, cho bất kỳ chức năng nào, đối với bất kỳ quy ước gọi điện nào và cho các hệ điều hành/nền tảng khác nhau. Một trong những vấn đề là nếu 5 byte mà bạn muốn ghi đè kết thúc ở giữa một lệnh. Để phát hiện "kết thúc của hướng dẫn", về cơ bản bạn cần phải bao gồm một bộ tách rời, bởi vì có thể có bất kỳ lệnh nào ở đầu hàm. Hoặc khi hàm này ngắn hơn 5 byte (một hàm luôn trả về 0 có thể được viết là XOR EAX,EAX; RETN
chỉ là 3 byte).
Hầu hết các trình biên dịch/trình biên dịch hiện tại tạo ra một hàm prolog dài 5 byte, chính xác cho mục đích này, hooking. Xem rằng MOV EDI, EDI
? Nếu bạn tự hỏi, "tại sao chúng lại di chuyển edi sang edi? Điều đó không làm gì cả !?" bạn hoàn toàn chính xác, nhưng đây là mục đích của prolog, chính xác là 5 byte (không phải là kết thúc ở giữa lệnh). Lưu ý rằng ví dụ tháo gỡ không phải là thứ tôi tạo ra, nó là calc.exe trên Windows Vista.
Phần còn lại của việc thực hiện móc chỉ là chi tiết kỹ thuật, nhưng chúng có thể mang lại cho bạn nhiều giờ đau, bởi vì đó là phần khó nhất. Ngoài ra hoạt động bạn đã mô tả trong câu hỏi của bạn:
void MyInstallRules(void)
{
if(PreHook() == block) // <-- First a 'pre' hook which can block the function
return;
int * val = InstallRules(); // <-- Call original function
PostHook(val); // <-- Call post hook, if interest of original functions return value
}
dường như còn tồi tệ hơn những gì tôi đã mô tả (và những gì Đường vòng không), ví dụ bạn có thể muốn "không gọi bản gốc", nhưng quay trở lại một số giá trị khác nhau. Hoặc gọi hàm gốc hai lần. Thay vào đó, hãy để trình xử lý hook của bạn quyết định xem nó sẽ gọi hàm ban đầu ở đâu và ở đâu. Ngoài ra, bạn không cần hai hàm xử lý cho một hook.
Nếu bạn không có đủ kiến thức về công nghệ bạn cần cho điều này (chủ yếu là lắp ráp), hoặc không biết cách làm móc, tôi khuyên bạn nên nghiên cứu những gì mà Detours làm. Hook nhị phân của riêng bạn và mất một trình gỡ lỗi (ví dụ OllyDbg) để xem ở cấp độ lắp ráp những gì nó chính xác đã làm, những gì hướng dẫn đã được đặt và ở đâu. Ngoài ra this tutorial có thể có ích.
Dù sao, nếu nhiệm vụ của bạn là móc một số chức năng trong một chương trình cụ thể, thì điều này là có thể thực hiện được và nếu bạn gặp bất kỳ sự cố nào, chỉ cần hỏi lại ở đây. Về cơ bản, bạn có thể làm rất nhiều giả định (như các prologs chức năng hoặc các quy ước được sử dụng) sẽ làm nhiệm vụ của bạn dễ dàng hơn nhiều.
Nếu bạn muốn tạo một số khung gắn kết đáng tin cậy, thì vẫn là một câu chuyện hoàn toàn khác và trước tiên bạn nên bắt đầu bằng cách tạo móc đơn giản cho một số ứng dụng đơn giản. Cũng cần lưu ý rằng kỹ thuật này không phải là hệ điều hành cụ thể, nó giống nhau trên tất cả các nền tảng x86, nó sẽ hoạt động trên cả Linux lẫn Windows. Điều gì là là Hệ điều hành cụ thể là bạn có thể sẽ phải thay đổi bảo vệ bộ nhớ của mã ("mở khóa" nó, vì vậy bạn có thể ghi vào nó), được thực hiện với mprotect
trên Linux và với VirtualProtect
trên Windows. Ngoài ra các quy ước gọi là khác nhau, đó là những gì bạn có thể giải quyết bằng cách sử dụng cú pháp chính xác trong trình biên dịch của bạn.
Một vấn đề khác là "DLL injection" (trên Linux nó có thể sẽ được gọi là "chia sẻ thư viện tiêm" nhưng thuật ngữ DLL injection được biết đến rộng rãi). Bạn cần phải đặt mã của bạn (thực hiện móc) vào chương trình. Đề xuất của tôi là nếu có thể, chỉ cần sử dụng biến môi trường LD_PRELOAD, trong đó bạn có thể chỉ định một thư viện sẽ được tải vào chương trình ngay trước khi nó chạy.Điều này đã được mô tả trong SO nhiều lần, như ở đây: What is the LD_PRELOAD trick?. Nếu bạn phải làm điều này trong thời gian chạy, tôi sợ bạn sẽ cần phải nhận được với gdb hoặc ptrace, mà theo ý kiến của tôi là khá khó khăn (ít nhất là điều ptrace) để làm. Tuy nhiên, bạn có thể đọc ví dụ this article on codeproject hoặc this ptrace tutorial.
Tôi cũng tìm thấy một số tài nguyên đẹp:
Ngoài ra một điểm khác: "Bản vá nội tuyến" này không phải là cách duy nhất để thực hiện việc này. Thậm chí còn có những cách đơn giản hơn, ví dụ: nếu chức năng là virtual hoặc nếu đó là chức năng xuất thư viện, bạn có thể bỏ qua tất cả việc lắp ráp/tháo gỡ/điều JMP và chỉ cần thay thế con trỏ đến hàm đó (trong bảng chức năng ảo hoặc trong bảng biểu tượng đã xuất).
Chỉ cần ném nó ra khỏi đó, bạn đã xem giải pháp phi kỹ thuật chưa, tức là * yêu cầu * tác giả cung cấp API? –
@KarlBielefeldt Đó sẽ là khó khăn ... GoldSrc (cho Half-Life) là khoảng 12 tuổi bây giờ tôi nghĩ? –