> For the complete documentation index, see [llms.txt](https://lightc.gitbook.io/pwn-gitbook/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lightc.gitbook.io/pwn-gitbook/kpwn/kpwn-tricks/some-syscall.md).

# some\_syscall

## 系统调用号

[syscall\_64.tbl - arch/x86/entry/syscalls/syscall\_64.tbl - Linux source code v7.0.10 - Bootlin Elixir Cross Referencer](https://elixir.bootlin.com/linux/v7.0.10/source/arch/x86/entry/syscalls/syscall_64.tbl)

## SYS\_sigreturn/SYS\_rt\_sigreturn

[setcontext | pwn-notes](https://sashactf.gitbook.io/pwn-notes/pwn/setcontext#longjmp)

在`SROP`中，我们通过使用`SYS_sigreturn/SYS_rt_sigreturn`的系统调用号`0xf`控制系统执行流

如何通过拥有一个可控第一个参数的函数调用原语来控制函数执行更无复杂的`ROP`，最好是`setcontext`，但是还有一种方法（缺点是会有指针加密）

我们可以认识一下`longjmp`

```c
#include <setjmp.h>

int setjmp(jmp_buf env);						// = int sigsetjmp(sigjmp_buf env, 1);
int sigsetjmp(sigjmp_buf env, int savesigs);

void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);
```

`longjmp`用于将执行流程从一个函数转移到另一个函数中预先设定的位置

`setjmp()` 函数动态建立后续控制转移的目标位置，而 `longjmp()` 则执行实际的执行流程转移

`setjmp()` 函数将上下文信息（通常包括栈指针、指令指针、可能还有其他寄存器的值以及信号掩码）保存到缓冲区 `env` 中，在此情况下，`setjmp()` 返回 `0`

`longjmp()` 函数利用 `env` 中保存的信息，将控制权转移回调用 `setjmp()` 的位置，并将栈“回滚”到调用 `setjmp()` 时的状态

当且仅当提供给 `sigsetjmp()` 的 `savesigs` 参数非零时，进程当前的信号掩码会被保存到 `env` 中，并且如果后续使用此 `env` 执行 `siglongjmp()`，该信号掩码将被恢复

直接调用 `setjmp()` 和 `sigsetjmp()` 时返回 `0`，在 `longjmp()` 或 `siglongjmp()` 执行后的第二次执行中，返回其 `val` 中指定的非零值

## SYS\_rt\_sigaction

[sigaction(2) - Linux manual page](https://www.man7.org/linux/man-pages/man2/sigaction.2.html)

`sigaction`用于改变进程在收到特定信号时所采取的动作

```c
#include <signal.h>

int sigaction(int signum,
              const struct sigaction *_Nullable restrict act,
              struct sigaction *_Nullable restrict oldact);
```

`signum` 指定信号，可以是除 `SIGKILL` 和 `SIGSTOP` 之外的任何有效信号

如果 `act` 非空，则从 `act` 安装信号 `signum` 的新动作，如果 `oldact` 非空，则将先前的动作保存到 `oldact` 中

```c
struct sigaction
  {
    /* Signal handler.  */
#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
    union
      {
	/* Used if SA_SIGINFO is not set.  */
	__sighandler_t sa_handler;
	/* Used if SA_SIGINFO is set.  */
	void (*sa_sigaction) (int, siginfo_t *, void *);
      }
    __sigaction_handler;
# define sa_handler	__sigaction_handler.sa_handler
# define sa_sigaction	__sigaction_handler.sa_sigaction
#else
    __sighandler_t sa_handler;
#endif

    /* Additional set of signals to be blocked.  */
    __sigset_t sa_mask;

    /* Special flags.  */
    int sa_flags;
  };
```

`sa_handler` 指定要与 `signum` 关联的动作，可以是以下之一

* `SIG_DFL` 表示默认行为
* `SIG_IGN` 表示忽略该信号
* 指向信号处理函数的指针，该函数仅接收信号编号作为其唯一参数

如果在 `sa_flags` 中指定了 `SA_SIGINFO`，则 `sa_sigaction` 被指定为 `signum` 的信号处理函数。该函数接收三个参数，如下

* `sig` 导致处理程序被调用的信号编号
* `info` 指向 `siginfo_t` 结构体的指针，结构体保存在栈上
* `ucontext` 这是一个指向 `ucontext_t` 结构体的指针，类型转换为 `void *`，结构体保存在栈上

```c
// https://elixir.bootlin.com/glibc/glibc-2.39/source/bits/types/siginfo_t.h
#include <bits/types.h>
#include <bits/types/__sigval_t.h>

typedef struct
  {
    int si_signo;		/* Signal number.  */
    int si_errno;		/* If non-zero, an errno value associated with
				   this signal, as defined in <errno.h>.  */
    int si_code;		/* Signal code.  */
    __pid_t si_pid;		/* Sending process ID.  */
    __uid_t si_uid;		/* Real user ID of sending process.  */
    void *si_addr;		/* Address of faulting instruction.  */
    int si_status;		/* Exit value or signal.  */
    long int si_band;		/* Band event for SIGPOLL.  */
    __sigval_t si_value;	/* Signal value.  */
  } siginfo_t;
```

`sa_mask` 指定了在执行信号处理程序期间应被阻塞的信号掩码（即添加到调用信号处理程序的线程的信号掩码中）。此外，除非使用了 `SA_NODEFER` 标志，否则触发处理程序的信号本身也会被阻塞

`sa_flags` 指定了一组用于修改信号行为的标志，它由零个或多个标志按位或运算组成

* `SA_SIGINFO`信号处理函数接受三个参数，此时应设置 `sa_sigaction` 而非 `sa_handler`

`sigaction()` 成功时返回 `0`；出错时返回 `-1`，并设置 `errno` 以指示错误

比如说处理段错误

```c
void sigsegv_handler(int sig, siginfo_t *si, void *context) {
	// ...
}

struct sigaction sa_segv = {0};
sa_segv.sa_sigaction = sigsegv_handler;
sa_segv.sa_flags = SA_SIGINFO;
sigemptyset(&sa_segv.sa_mask);
sigaction(SIGSEGV, &sa_segv, NULL);
```
