2013-06-10 44 views
5

tôi đã được đọc một bài báo về x86 API hooking demystified x86 hooking, và tôi đi qua mã này:Chức năng opcode trong C

if(*function_A == 0xe9) { 
    printf("Hook detected in function A.\n"); 
} 

Có vẻ như rằng mã này kiểm tra liệu các opcode của hàm là một bước nhảy. Câu hỏi của tôi là về cú pháp *function_A. cú pháp này là gì? Liệu nó trả về opcode của một hàm trong C? Tôi đã thực hiện rất nhiều nghiên cứu nhưng tôi đã không tìm thấy bất kỳ tài liệu hướng dẫn về tính năng này

EDIT

Tôi nghĩ tôi đã thêm các liên kết đến bài viết nhưng tôi chỉ nhận thấy tôi quên để thêm vào. Liên kết được thêm vào trong trường hợp nó giúp.

+1

Loại 'function_A' là gì? Giá trị của nó đến từ đâu? – interjay

+0

Đây là nguyên mẫu 'void function_A (int value, int value2);' – Mansuro

+2

Sau đó, mã đó sai, nó sẽ so sánh con trỏ hàm và không phải là mã opcode. – interjay

Trả lời

5

Không, bạn không thể coi trọng con trỏ hàm để lấy mã cơ bản.

Điều này có thể được thực hiện bằng cách giới thiệu một con trỏ khác và dựa vào nền tảng cụ thể "làm điều đúng", nơi "đúng" có nghĩa là "những gì tôi muốn làm".

Cái gì như:

const unsigned char *function_A = (unsigned char *) printf; /* Any function. */ 

Đây không phải là di động, và sẽ tạo ra cảnh báo trình biên dịch từ chức năng và dữ liệu con trỏ không tương thích. Ví dụ: x86, nó có lẽ sẽ "làm việc".

+0

Vâng, khi ABI nói điều gì khác với Tiêu chuẩn, chúng ta có nên tiếp tục giữ luật sư ngôn ngữ và khăng khăng rằng nó không chính xác? (Tôi có nghĩa là, mọi người đang viết mã shell mà làm việc với một lời giải thích hợp lý.) (Và tôi không cố gắng để được trolling ở đây, chỉ quan tâm.) –

+2

Và 1 anyway. Từ một quan điểm khác: trong POSIX, 'void *' tương thích với cả hai con trỏ dữ liệu và hàm. Điều này có nghĩa là 'void * tmp = & printf; const unsigned char * funcPtr = tmp; 'hoạt động mà không có cảnh báo. –

+0

Bài tập có thể hoạt động mà không có cảnh báo, nhưng nó sẽ thực hiện, người đọc của mã nghĩ rằng nó nên làm gì? – Devolus

3

Nếu bạn làm điều gì đó như thế này:

unsigned char *pf; 

pf = (unsigned char *)function_A; 

if (*pf == 0xE9) 
{ 
... 
} 

sau đó bạn sẽ nhận được hiệu ứng đó (giả sử kiến ​​trúc cho phép đọc mã nói chung, và trình biên dịch hiện hành vi undefined quyền đạt được điều này).

Tuy nhiên, trừ khi bạn quét toàn bộ hàm trong mã, bạn có thể dễ dàng bỏ qua sơ đồ phát hiện bằng cách đặt lệnh nhảy (0xe9 là bước nhảy đến địa chỉ tương đối) ở nơi khác hoặc sử dụng một dạng nhảy khác hướng dẫn (0x66 0xe9 và độ lệch 16 hoặc 32 bit trong kiến ​​trúc 32 bit tương ứng, ví dụ). Và tất nhiên, nếu bạn chỉ muốn ghi đè hàm điểm trong một hàm dài hơn, việc sửa đổi một vài byte trong hàm đó để thay đổi score += 10 thành score += 120 sẽ không quá khó. Có thể thay đổi thành score += 10000 có thể khó hơn, vì thường có các biến thể "số lượng nhỏ" và "số lượng lớn" của hướng dẫn cộng và trừ.