我正在嘗試使用sys_brk syscall在linux中分配一些內存.這是我嘗試過的:
BYTES_TO_ALLOCATE equ 0x08
section .text
global _start
_start:
mov rax, 12
mov rdi, BYTES_TO_ALLOCATE
syscall
mov rax, 60
syscall
根據linux調用約定,我希望返回值在rax寄存器中(指向已分配內存的指針).我在gdb中運行它,在進行sys_brk系統調用之后,我注意到以下寄存器內容
在系統調用之前
rax 0xc 12
rbx 0x0 0
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x8 8
在系統調用之后
rax 0x401000 4198400
rbx 0x0 0
rcx 0x40008c 4194444 ;
rdx 0x0 0
rsi 0x0 0
rdi 0x8 8
在這種情況下,我不太了解rcx寄存器中的值.哪一個用作指向我用sys_brk分配的8個字節的開頭的指針?
解決方法:
請注意,sys_brk的界面與brk / sbrk POSIX函數略有不同;請參閱C library/kernel differences section of the Linux brk(2) man page.具體來說,Linux sys_brk設置程序中斷; arg和返回值都是指針.見Assembly x86 brk() call use.這個答案需要upvotes,因為它是該問題上唯一的好處.
你問題的另一個有趣的部分是:
I do not quite understand the value in the rcx register in this case
您正在看到syscall/sysret指令如何設計為允許內核恢復用戶空間執行但仍然很快的機制.
系統調用不執行任何加載或存儲,它只修改寄存器.它不使用特殊寄存器來保存返回地址,而只使用常規整數寄存器.
在內核返回到用戶空間代碼之后,RCX = RIP和R11 = RFLAGS并不是巧合.這種情況的唯一方法是,如果ptrace系統調用在內核中修改了進程保存的rcx或r11值. (ptrace是gdb使用的系統調用).在這種情況下,Linux將使用iret而不是sysret返回用戶空間,因為較慢的通用情況iret可以做到這一點. (有關Linux系統調用入口點的一些演練,請參閱What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?.但是,大多數情況下,32位進程的入口點,而不是64位進程中的系統調用.)
而不是將返回地址推送到內核堆棧(如int 0x80),系統調用:
>設置RCX = RIP,R11 = RFLAGS(因此在執行系統調用之前,內核甚至無法查看這些寄存器的原始值).
>使用配置寄存器(IA32_FMASK MSR)中的預配置掩碼屏蔽RFLAGS.這讓內核禁用中斷(IF),直到它完成swapgs并將rsp設置為指向內核堆棧.即使將cli作為入口點的第一條指令,也會有一個漏洞的窗口.你也可以通過屏蔽DF來免費獲得cld,所以即使用戶空間使用了std,rep movs / stos也會向上移動.
有趣的事實:AMD首次提出的系統調用/交換設計并未掩蓋RFLAGS,而是掩蓋了they changed it after feedback from kernel developers on the amd64 mailing list(在?2000年,比第一個芯片早幾年).
>跳轉到配置的系統調用入口點(設置CS:RIP = IA32_LSTAR).我想,舊的CS值不會保存在任何地方.
>它沒有做任何其他事情,內核必須使用swapgs來訪問保存內核堆棧指針的信息塊,因為rsp仍然有來自用戶空間的值.
因此,系統調用的設計需要一個系統調用ABI,其中注冊符號,這就是為什么這些值是它們的原因.
標簽:linux,assembly,x86-64,system-calls
來源: https://codeday.me/bug/20190828/1749140.html