2011-10-28 34 views
8

Tôi đang sử dụng Linux với x86 (chính xác 64 bit). Có cách nào tôi có thể nhận được địa chỉ của hướng dẫn hiện tại. Thực ra tôi muốn viết các phiên bản đơn giản của riêng mình là setjmp/longjmp. Here, R .. đã đăng phiên bản đơn giản của longjmp. Bất kỳ ý tưởng làm thế nào setjmp được thực hiện. Một phiên bản được đơn giản hóa, mà không tính đến ngoại lệ và tín hiệu, v.v ...Nhận địa chỉ hướng dẫn hiện tại cho x86

Trả lời

24

Tôi tin vào mã 64 bit bạn chỉ cần thực hiện lea rax, [rip].

32-bit thành ngữ là:

 call next 
next: pop eax 
+0

Và có thể thực hiện điều gì đó tương tự trong 32 bit không? – MetallicPriest

+1

@MetallicPriest: Đã cập nhật câu trả lời. – NPE

+0

Bí quyết tuyệt vời hun :-p! – MetallicPriest

0

This trang web đưa ra một phiên bản đơn giản của setjmp và longjmp, mà là như sau.

#include "setjmp.h" 

#define OFS_EBP 0 
#define OFS_EBX 4 
#define OFS_EDI 8 
#define OFS_ESI 12 
#define OFS_ESP 16 
#define OFS_EIP 20 

__declspec(naked) int setjmp(jmp_buf env) 
{ 
    __asm 
    { 
    mov edx, 4[esp]   // Get jmp_buf pointer 
    mov eax, [esp]   // Save EIP 
    mov OFS_EIP[edx], eax 
    mov OFS_EBP[edx], ebp // Save EBP, EBX, EDI, ESI, and ESP 
    mov OFS_EBX[edx], ebx 
    mov OFS_EDI[edx], edi 
    mov OFS_ESI[edx], esi 
    mov OFS_ESP[edx], esp 
    xor eax, eax    // Return 0 
    ret 
    } 
} 

__declspec(naked) void longjmp(jmp_buf env, int value) 
{ 
    __asm 
    { 
    mov edx, 4[esp]   // Get jmp_buf pointer 
    mov eax, 8[esp]   // Get return value (eax) 

    mov esp, OFS_ESP[edx] // Switch to new stack position 
    mov ebx, OFS_EIP[edx] // Get new EIP value and set as return address 
    mov [esp], ebx 

    mov ebp, OFS_EBP[edx] // Restore EBP, EBX, EDI, and ESI 
    mov ebx, OFS_EBX[edx] 
    mov edi, OFS_EDI[edx] 
    mov esi, OFS_ESI[edx] 

    ret 
    } 
} 
+3

Đây có phải là câu trả lời cho câu hỏi của bạn không, @MetallicPriest? – karlphillip

+0

Không nhất thiết, tôi có thể đánh dấu câu trả lời của bạn, nếu nó tốt :-p! – MetallicPriest

4

Không thể truy cập đăng ký bù trừ vào hiện tại (EIP). Tuy nhiên, có một cách hackish-cách để đọc nó gián tiếp - bạn lừa chương trình vào đẩy giá trị của EIP vào ngăn xếp, sau đó chỉ cần đọc nó đi. Bạn có thể tạo ra một chương trình con đó trông như thế này:

GetAddress: 
    mov eax, [esp] 
    ret 
... 
    call GetAddress  ; address of this line stored in eax 

Hoặc, thậm chí đơn giản hơn:

call NextLine 
NextLine: 
    pop eax    ; address of previous line stored in EAX 

Nếu bạn sử dụng một hướng dẫn CALL FAR, giá trị phân khúc (CS) sẽ được đẩy vào stack cũng .


Nếu bạn đang sử dụng C, có nhiều tiện ích mở rộng C dành riêng cho trình biên dịch bạn có thể sử dụng trên this page. Xem thêm this interesting article.

+0

OP hỏi về x86_64, có địa chỉ tương đối, do đó, có hướng dẫn "có thể truy cập" tới RIP –

8

Nếu sử dụng GCC, bạn cũng có thể sử dụng __builtin_return_address

+2

Hãy nhớ rằng bạn sẽ cần bọc nó trong một hàm để có hiệu ứng dự định, nếu không bạn sẽ kết thúc với địa chỉ trả về cho khung ngăn xếp hiện tại thay vì địa chỉ của lệnh hiện tại. – Jason

+2

nếu sử dụng GCC, việc sử dụng ['somelabel: return && somelabel;'] (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html) –

+1

@Jason sẽ dễ dàng hơn và cũng đảm bảo định nghĩa của hàm bao hàm chứa __builtin_return_address không nằm trong tệp tiêu đề và sẽ không bao giờ được gạch chân. –

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