2013-05-07 40 views

Trả lời

7

Cuộc gọi và nhảy gián tiếp có * sau chỉ dẫn và trước vị trí như trong callq *%r13jmpq *0x204d8a(%rip).

Tôi sẽ chỉ cho hai ví dụ thực tế từ x86-64 Linux máy của tôi:

  1. qsort() trong thư viện chuẩn C gọi người dùng cung cấp chức năng so sánh
  2. Một kêu gọi thực thi tự động liên kết strcmp()

Các qsort() thực hiện trong glibc thực sự gọi loại khác nhau một các thuật toán tùy thuộc vào kích thước đầu vào. Một ví dụ thực hiện là msort_with_tmp() trong /lib64/libc.so.6:

0000003cbde37d70 <msort_with_tmp.part.0>: 
    <...> 
    3cbde37dd6: 4c 8b 68 10    mov 0x10(%rax),%r13 
    <...> 
    3cbde37e2f: 41 ff d5    callq *%r13 

Đoạn mã trên di chuyển địa chỉ của hàm so sánh vào R13 và cuối cùng thực hiện một cuộc gọi gián tiếp.

Đối với một thực thi tự động liên kết gọi strcmp(), tôi sẽ sử dụng /bin/đúng làm ví dụ. Tất cả các cuộc gọi đến strcmp() trong thực thi chính được dịch sang một cuộc gọi đến stub PLT, strcmp @ plt:

$ gdb /bin/true 
(gdb) disassemble '[email protected]' 
0x401350 <+0>: ff 25 8a 4d 20 00 jmpq *0x204d8a(%rip) # 0x6060e0 <[email protected]> 
0x401356 <+6>: 68 19 00 00 00 pushq $0x19 
0x40135b <+11>: e9 50 fe ff ff jmpq 0x4011b0 

Trong hướng dẫn đầu tiên, 0x204d8a (% rip) sử dụng RIP địa chỉ tương đối để định vị [email protected].

Nếu chúng ta cố gắng để kiểm tra những gì giá trị [email protected] nắm giữ trong thời gian chạy:

(gdb) break *0x401350 
(gdb) run --XXX 
Breakpoint 1, 0x0000000000401350 in [email protected]() 

(gdb) p/a '[email protected]' 
$1 = 0x3cbdf2fbe0 <__strcmp_sse42> 
(gdb) break *0x3cbdf2fbe0 
Breakpoint 2 at 0x3cbdf2fbe0: file ../sysdeps/x86_64/multiarch/strcmp-sse42.S, line 128. 
(gdb) continue 
Continuing. 

Breakpoint 2, __strcmp_sse42() 
    at ../sysdeps/x86_64/multiarch/strcmp-sse42.S:128 
128  mov %esi, %ecx 

Chúng ta thấy rằng [email protected] điểm để __strcmp_sse42() trong /usr /lib64/libc.so.6.

Do đó nhảy đầu tiên gián tiếp chúng tôi gặp nhau, jmpq * 0x204d8a (% rip) trong strcmp @ plt, kết thúc lên nhảy đến __strcmp_sse42(). Đây là cơ chế STT_GNU_IFUNC đang hoạt động. Nó sử dụng trình liên kết động để tìm ra strcmp() biến thể phù hợp nhất khi chạy dựa trên khả năng của CPU.

0

Trên CPU x86-64, lệnh gọi và lệnh nhảy hoàn toàn tương đối% rip.

Vì vậy, các chế độ liên quan là:

jmpq $6 # Direct, relative: Jump to %rip+0x6 
jmpq *$6 # Direct, absolute: Jump to 0x6 
jmpq %r13 # Indirect, relative: Jump to %rip+%r13 
jmpq *%r13 # Indirect, absolute: Jump to %r13. Aka "movq %r13, %rip" 

Và sau đó các phương thức gấp đôi gián tiếp:

jmpq 0x20(%r13) # Jump to %rip + *(%r13 + 0x20). 
jmpq *0x20(%r13) # Jump to *(%r13 + 0x20) 

Phương thức giải quyết cuối cùng là rất thường thấy trong C++ tháo gỡ như

callq *0x20(%r13) 

trong đó% r13 chứa địa chỉ của vtable. Vì vậy, nó tìm kiếm mục nhập trong vtable tại offset 0x20 và sau đó gọi hàm được trỏ đến bởi mục nhập đó. Chế độ luôn luôn tuyệt đối (nghĩa là không phải% tương đối rip) vì vtable được sử dụng từ nhiều trang web cuộc gọi, do đó,% rip relative sẽ không có ý nghĩa gì.

+0

Và 'chuyển đổi 'và các cuộc gọi con trỏ hàm. –

Các vấn đề liên quan