系统调用是用户程序和linux内核交互的接口,linux的系统调用有下面三种方式:
int 80
在x86与x86_64的系统中,都可以使用int $0x80指令来执行系统调用,参数使用如下:
调用号 | 参数1 | 参数2 | 参数3 | 参数4 | 参数5 | 参数6 | 返回值 |
---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | ebp | eax |
syscall
x86_64引入了一个新指令syscall来执行系统调用,参数使用如下:
调用号 | 参数1 | 参数2 | 参数3 | 参数4 | 参数5 | 参数6 | 返回值 |
---|---|---|---|---|---|---|---|
rax | rdi | rsi | rdx | r10 | r8 | r9 | rax |
库函数
正常调用库函数(man 3 execve
),传参方式见x86 调用约定
查看调用号与参数
查看调用号:头文件/usr/include/asm/unistd.h
内容如下,所以32位和64位的调用号可以分别在unistd_32.h和unistd_64.h中找到
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_X86_UNISTD_H
#define _ASM_X86_UNISTD_H
/* x32 syscall flag bit */
#define __X32_SYSCALL_BIT 0x40000000UL
# ifdef __i386__
# include <asm/unistd_32.h>
# elif defined(__ILP32__)
# include <asm/unistd_x32.h>
# else
# include <asm/unistd_64.h>
# endif
#endif /* _ASM_X86_UNISTD_H */
查看参数:man 2 execve
示例
以execve
为例,man 2 execve
查看其接口如下:int execve(const char *pathname, char *const argv[], char *const envp[]);
下面汇编实现了execve("/bin/sh", 0, 0)
:
32位:
xor ecx, ecx
push 0x0b
pop eax
cdq
push 0x68732f
push 0x6e69622f
mov ebx, esp
int 0x80
64位:
mov rdx, 0x68732f6e69622f
push rdx
push rsp
pop rdi
xor rsi, rsi
xor rdx, rdx
push 59
pop rax
syscall
网友评论