Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
工具/GitHubGitHub/yeet-src/sigwire
动态分析 (沙盒)调试器取证分析事件响应日志分析
GitHubyeet-src/sigwire

sigwire

实时内核信号可观测性工具,利用 eBPF 跟踪点流式传输 Linux 主机上引发的每个信号,实时显示发送者、目标、处置方式、处理程序延迟以及系统调用中断。

查看仓库
159410天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享
网站

sigwire

tail -f 用于信号。 系统上每个进程引发的每个信号——谁发送的、谁接收的、哪个信号、如何引发的(kill(2)、内核、POSIX 定时器)、目标是否捕获了它以及其处理程序运行了多长时间、它是否用 EINTR 撕开了阻塞的系统调用——从内核的信号跟踪点解码并实时流式传输到您的终端。无需对单一 pid 使用 strace -f,无需 ptrace,无需被涉及进程的配合。

Linux yeet + eBPF Dual BSD/GPL Discord

sigwire streaming live signals as a switchboard in the terminal

sigwire 将内核的信号机制转变为实时配线架:每一行是 sender ──SIGNAL──▶ target,按严重性着色,标记引发方式,目标是否捕获了它(以及其处理程序运行了多长时间),是否中断了阻塞的系统调用**(↯ EINTR read),当某个信号大量出现时折叠为 ×N,并且当它是真正的致命一击时标记 ☠。** 侧边栏统计着传输中的信号;暂停并选择一行以查看完整画面——信号处置、处理程序地址、sigaction 标志以及目标当时正在阻塞的信号。

因为它挂钩内核的跟踪点,而不是任何单一进程,一次运行即可同时监控主机上的每个信号——您的应用程序、监督程序、内核自身的故障机制——而它们都不会意识到自己正在被跟踪。

[!TIP] 每个信号的两个方面。 sigwire 同时监控 signal:signal_generate(发送者的视角——谁引发了什么,配线架线路)和 signal:signal_deliver(目标的视角——是否捕获了它,使用哪个处理程序和标志,当时阻塞了什么,以及是否中断了系统调用)。另外两个钩子——rt_sigreturn(2) 和系统调用退出跟踪点——对处理程序进行计时并捕获 EINTR。所有这些都被关联回同一行。这种分离也是为什么 ☠ fatal 计数故意保守的原因(参见什么算作致命):信号的产生发生在传递之前,因此发送方无法知道信号的命运——只有传递方可以,而且仅限于它观察到的情况。

快速开始```sh

curl -fsSL https://yeet.cx | sh # install the yeet daemon (one time) yeet run github:yeet-src/sigwire # run the dashboard (the daemon does the privileged BPF load)

root@kitploit:~
[手动安装指南](https://yeet.cx/docs/manual-installation) | 仅限 Linux

无需配置 — 信号在任何机器上都是持续的背景流量,因此行会立即从顶部开始出现。想自己生成一些?`kill -USR1 <pid>`、对前台作业按 `Ctrl-C`,或者启动任何托管运行时并观察其 GC/调度器 ping 自己的线程(`↯ EINTR futex` 滚动而过)。

## 控制

信号流默认跟随最新信号;选择一行或暂停后,它会保持静止,同时数据在下方继续流动。

| 键 | 操作 |
| --- | ------ |
| `p` · `Space` | 暂停/恢复信号流(冻结以阅读) |
| `↑`/`↓`, `k`/`j` | 暂停并检查一行 — 打开详情面板 |
| `/` | 模糊过滤 — 匹配进程、PID、信号、来源和处置方式;匹配字符实时高亮 |
| `e` | 过滤至**仅中断的系统调用**(`↯ EINTR` / `↺ restarted`) |
| `s` | 打开**信号选择器** — 实时静音或显示任何信号 |
| `Esc` | 退出一层 — 清除过滤/关闭选择器/取消选择,然后退出 |
| `q` | 退出 |

## 您正在查看的内容

每一行是一个生成的信号,最新的在最顶部:```
 WHEN            SENDER  SIGNAL        TARGET               NOTE
  now       bash·4402──SIGINT───▶  node·8813        kill(2)  ↯ EINTR read  caught 41µs
 1.2s    systemd·1──────SIGTERM──▶  nginx·1291       kill(2)  caught 1.2ms
 3.4s     kernel·8813──SIGSEGV──▶  chrome·8813       fault    default  ☠
 4.1s   postgres·507──SIGUSR1───▶  postgres·509 ×6  kill(2)  caught 9µs

每一行都是一个块:发送方 → 目标 为 comm·pid(发送方是发起信号的一方,current;目标是信号指向的进程),中间的导线承载着根据严重性着色的信号名称,×N 将相同信号的一次突发合并为一行,右侧的注释给出来源,然后是任何系统调用中断,最后是处置方式。

每一行在交付解析完成时冻结,此后永远不会再改变——因此一次突发会作为一条稳定的日志滚动显示,而不是闪烁的聚合。

导线根据严重性着色,采用与 UI 其余部分相同的 256 色调色板:

注释 是来源(kill(2)、tgkill、sigqueue、timer、kernel、fault);然后,如果它中断了阻塞的系统调用,会显示 ↯ EINTR read(或 ↺ restarted read,当 SA_RESTART 自动恢复它时);最后是处置方式——caught 41µs(处理程序运行了,以及耗时多久)、default(没有处理程序,采用了默认行为)或 ⊘ ignored。☠ 标记真正的致命一击(参见什么算致命)。

[!NOTE] ↯ EINTR 是需要关注的重点。 当一个信号到达时,线程正阻塞在慢速系统调用(read、poll、accept、futex、nanosleep……)中,该线程会被强制唤醒:系统调用返回 -1 / EINTR,并且除非处理程序设置了 SA_RESTART,否则它不会恢复——应用程序必须重试。忘记这一点是一个经典的、令人抓狂的、与时机相关的 bug(“为什么我的 read() 失败了一次?”)。sigwire 实时显示这种情况的发生,以及是哪个系统调用受到了影响。按 e 键隐藏所有其他内容,只观察这些中断。

右侧的轨道是聚合视图:按数量排列的顶部信号、按来源的分类,以及交付统计——捕获了多少信号、默认处理了多少、忽略了多少。

检查信号

按 ↑/↓(或 p)冻结流并选择一行;轨道变为一个详细信息面板,显示关于该确切信号的交付侧所知的一切:``` SIGNAL SIGUSR1 (10) user from ctarget·3980913 to ctarget·3980913 RAISED via tgkill code SI_TKILL scope thread result delivered DELIVERY handled caught syscall EINTR ← read handler 0x55f0a1c3 ran 3.0ms flags SA_SIGINFO TARGET BLOCKS SIGINT SIGQUIT SIGTERM

root@kitploit:~
- **handled** — `caught`(运行了用户空间处理程序)、`default`(→ 默认动作:终止/核心转储/停止/忽略)或 `ignored`。
- **syscall** — 如果该信号中断了一个阻塞的系统调用:`EINTR ← read`(用户空间看到 `EINTR`)或 `restarted read`(`SA_RESTART` 透明地恢复它)。
- **ran** — 处理程序执行的时间,从递送到结束它的 `rt_sigreturn(2)` 计算。(只会在 C 处理程序中设置标志并在以后执行实际工作的运行时——CPython、Go——在这里显示一个很小的时间;那是它们的问题,不是 sigwire 的。)
- **flags** — 处理程序上的 `sigaction` 标志(`SA_RESTART`、`SA_SIGINFO`、`SA_NODEFER`……)。
- **TARGET BLOCKS** — 目标在递送时刻已阻塞的信号(其 `sigprocmask`),直接来自其 `task_struct`。

`Esc` 关闭检查器;`p` 恢复实时显示。

## 什么算作致命

`☠ fatal` 计数器和 `☠` 行徽章故意严格。因为 `signal_generate` 在*产生*时触发,sigwire 无法看到目标是否安装了处理程序——`SIGTERM` 可能被捕获并转换为干净关闭,或者完全被忽略。因此,只有当死亡是明确无误时,它才会计数:

- **`SIGKILL` 递送**——不可捕获、不可忽略、始终致命;**或**
- **内核自身引发的**(同步故障,而非用户空间的 `kill`)一个**核心转储信号**(`SEGV`/`BUS`/`ABRT`/`ILL`/`FPE`/`TRAP`/`SYS`/`QUIT`)。

其他所有信号——来自 `systemd` 的 `SIGTERM`、来自你的 `Ctrl-C` 的 `SIGINT`、运行时发给自己线程的 `SIGPWR`——都会被显示和着色,但不计为死亡,因为很可能不是。

## 信号选择器(一个实时的内核旋钮)

在任何繁忙的机器上,三个信号都是纯背景噪音:`SIGCHLD`(每次子进程回收)、`SIGURG`(Go 的异步抢占心跳)和 `SIGWINCH`(终端大小变化,广播给所有前台进程)。sigwire 默认在**内核内**静音这三个信号,以便显示感兴趣流量——但哪些信号是噪音取决于你。

按下 `s` 打开**信号选择器**:一个模态列表,包含每个信号及其实时严重性颜色和你已经看到的数量,每个信号可在 `shown`(显示)和 `muted`(静音)之间切换。用箭头移动到某个信号(或**输入其数字**——`1`、`5` → 跳到 15),然后按 `space`,该信号立即切换。`a` 一次性切换**所有**信号。标题栏中的 `muted` 计数跟踪当前隐藏的数量。

这是演示的双向部分:静音掩码是正在运行的 BPF 程序的 `.data` 部分中的一个 `__u64` 全局变量,切换一行会通过 `DataSec.patch()` 修补匹配的位,而程序持续运行。内核在静音信号到达环形缓冲区之前就丢弃它们,因此静音不会消耗任何成本——而且取消静音会在流式过程中恢复信号,无需重新加载。

## 工作原理

核心是 [`src/bpf/sigwire.bpf.c`](https://github.com/yeet-src/sigwire/blob/HEAD/src/bpf/sigwire.bpf.c) + [`src/bpf/deliver.bpf.c`](https://github.com/yeet-src/sigwire/blob/HEAD/src/bpf/deliver.bpf.c)(内核,链接成一个对象)和 [`src/probes/sigwire.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/sigwire.js)(用户空间)。所有内容通过 `(target tid, signal)` 关联。

### BPF 侧

两个源文件链接成一个可加载对象 `bin/probe.bpf.o`,包含四个 tracepoint 程序:

| 程序 | 附加到 | 捕获内容 |
|---|---|---|
| `on_signal_generate` | `signal:signal_generate` | 发送者(`current`)+ 目标(`comm`/`pid`)、信号、`si_code`、`group` 标志、`result`——如果该信号的位在实时 `mute_mask` 中设置,则在内核中丢弃 |
| `on_signal_deliver` | `signal:signal_deliver` | 目标的处置(`sa_handler`)、`sa_flags`,以及来自 `task_struct` 的 `blocked` 信号集;为处理程序计时标记递送 |
| (rt_sigreturn) | `syscalls:sys_enter_rt_sigreturn` | 与标记的递送进行差异比较,得到处理程序的运行时间 |
| (sys_exit) | `raw_syscalls:sys_exit` | 记录罕见的 `-ERESTART*` 返回值,以便下一个 `signal_deliver` 将其解析为 `EINTR`/`restarted` 以及被中断的系统调用号 |

映射连接内核和用户空间:

- `events` — `RINGBUF`,每次产生一个 `signal_event`。
- `dispatch` — `RINGBUF`,每次递送/处理程序返回一个 `dispatch_event`。
- `mute_mask` — `.data` 部分中的一个 `__u64` 全局变量;选择器通过修补单个位在内核中丢弃信号。
- `handler_start` / `restart_pending` — `HASH`,以 tid 为键,每个线程的临时空间,用于将一次递送与其 `rt_sigreturn` 配对,以及将系统调用的 `-ERESTART*` 退出与后续递送配对。

### JS 侧

| 文件 | 职责 |
|---|---|
| [`src/probes/probe.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/probe.js) | 加载 `bin/probe.bpf.o` 一次,绑定映射,启动程序(它们自动附加) |
| [`src/probes/sigwire.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/probes/sigwire.js) | 唯一的 BPF 感知数据模块:将两个环形缓冲区折叠成一个滚动 feed 并带有统计,将递送关联到产生,拥有静音掩码旋钮——暴露 `feed`、`visible`、`muteMask` 信号 |
| [`src/main.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/main.jsx) | 组合根:输入、选择、响应式布局(窄终端上隐藏侧栏)、`mount` |
| [`src/components/feed.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/feed.jsx) | 交换机板:`发送者 ──SIG──▶ 目标`、处置/延迟、徽章、色调、合并 |
| [`src/components/tally.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/tally.jsx) | 侧栏——顶部信号、按来源分解、递送统计 |
| [`src/components/detail.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/detail.jsx) | 检查器——每个信号的处置、处理程序、标志、阻塞掩码 |
| [`src/components/picker.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/picker.jsx) | 信号选择器模态框——通过内核静音掩码静音/显示每个信号 |
| [`src/components/titlebar.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/titlebar.jsx) | 品牌、实时速率、总计、`☠ fatal` 计数器、静音计数、实时/暂停 |
| [`src/components/footer.jsx`](https://github.com/yeet-src/sigwire/blob/HEAD/src/components/footer.jsx) | 按键提示和实时过滤提示 |
| [`src/lib/signals.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/signals.js) | 唯一真相来源:名称、严重性、颜色、`si_code` → 来源、处置、标志、掩码解码、致命性 |
| [`src/lib/format.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/format.js) | 纯格式化器——填充、截断、`ago()`、持续时间、紧凑计数 |
| [`src/lib/fuzzy.js`](https://github.com/yeet-src/sigwire/blob/HEAD/src/lib/fuzzy.js) | 对进程+pid+信号+来源+处置的子序列模糊匹配 |

该模型是一个滚动的**产生信号 feed**,将相同的重复合并成 `×N` 行。一个信号的产生行在其递送解析后立即冻结——因此屏幕上已存在的行永远不会更改或跳跃。一个 120 毫秒的窗口计时器每帧发布一个快照,因此繁忙的环形缓冲区只需一次重新渲染,而不是数千次。

### 为什么使用 tracepoint,而不是 `strace`/`ptrace`

`strace -f` 跟踪一个进程树并在每次事件时停止跟踪对象;`ptrace` 针对每个目标且具有侵入性。信号 tracepoint 是*内核*对所有进程引发和递送信号的接缝,无需每个应用设置,且不会停止任何人。将产生 ↔ 递送 ↔ `rt_sigreturn` 配对,可以得到发送者/目标对、处置、每个处理程序的延迟以及 EINTR 判定,从而将信号的整个生命周期串联起来。

## 跨内核测试

`make veristat` 在**你的**内核上使用 veristat 加载 `bin/probe.bpf.o`——快速检查每个程序是否通过验证器,以及每个程序的复杂度(insns/states)。加载 BPF 需要权限,因此使用 `sudo`。

在你的笔记本上加载的程序可能会被较旧内核的验证器拒绝。[`.github/workflows/kernel-matrix.yml`](https://github.com/yeet-src/sigwire/blob/HEAD/.github/workflows/kernel-matrix.yml) 可以防止这种情况:对于矩阵中的每个内核,它构建对象,在虚拟机([cilium's little-vm-helper](https://github.com/cilium/little-vm-helper),使用 `quay.io/lvh-images` 的镜像)中启动该内核,并针对它运行供应商提供的静态 **veristat**——如果验证器拒绝任何程序则作业失败,并将每个内核的结果透视成一个 ✅/❌ 网格。虚拟机中的门控脚本是 [`build/verify-kernel.sh`](https://github.com/yeet-src/sigwire/blob/HEAD/build/verify-kernel.sh)。

使用 `make veristat-matrix` 在本地(Linux + KVM)运行相同的矩阵——它使用 `lvh` + QEMU 启动内核映像,并打印一个 `ok`/`FAIL` 网格。使用 `make veristat-matrix KERNELS="6.6 bpf-next"` 选择内核。

## 要求

> [!重要]
> - **一个带有 BTF**(`CONFIG_DEBUG_INFO_BTF`)的 Linux 内核,用于 CO-RE——`bpftool` 从它生成 `src/bpf/include/vmlinux.h`。在当前的 Arch、Fedora、Ubuntu 和 Debian(自 ~5.4 以来的每个主流发行版内核)上默认启用。
> - **yeet 守护进程**,执行特权的 BPF 加载。BPF 能力被委托给一个守护进程,因此 `sigwire` 本身以无特权方式运行。`curl -fsSL https://yeet.cx | sh` 安装它。
>
> 要从源代码构建,你还需要 `clang` 和 `bpftool`——但供应商提供的静态工具链提供了它们,因此你不需要系统的 C/BPF 工具链。不需要 node/npm:esbuild 也是供应商提供的,并且该项目没有第三方依赖项。

## 诚实的注意事项

> [!注意]
> `sigwire` 是观测,而非强制执行。它显示被引发的内容;它不会阻塞、延迟或改变任何信号。

- **一行是一个*被引发的*信号。** 交换机板行来自产生阶段;目标可能捕获它、阻塞它或已经退出。处置/处理程序/掩码列来自*递送*侧,并且只有在内核实际递送时才填充——一个被阻塞或仍处于待决状态的信号不会显示处置。参见[什么算作致命](#什么算作致命)。
- **关联是尽力而为的。** 产生和递送是分开的 tracepoint,没有共享 ID,通过 `(目标 tid, 信号)` 在一个时间窗口内匹配。在同一线程的相同信号风暴下,配对可能会模糊;但在绝大多数常见情况下是正确的。
- **处理程序计时测量内核框架,而非你的意图。** `ran` 是从递送到 `rt_sigreturn`。一个只设置标志的处理程序(CPython、Go 的运行时代码)在微秒内返回,即使“真正”的工作稍后发生在事件循环中——准确,但可能不是你期望的。
- **EINTR 检测监视每个系统调用退出。** 捕获被中断的系统调用需要附加到 `raw_syscalls:sys_exit`,它在系统范围内的*每个*系统调用返回时触发(处理程序立即放弃所有除罕见 `-ERESTART*` 代码外的其他代码,因此额外成本是每个系统调用几条指令——但它并非为零)。系统调用*名称*是 x86-64 表;其他架构显示原始系统调用编号。
- **内核信号的发送者是 `current`。** 对于同步故障(来自错误访问的 `SIGSEGV`),那是故障任务本身——正确且有用。对于异步内核信号,`current` 是内核引发信号时正在运行的任何任务,这是一个提示,而非绝对真理。
- **实时信号编号是名义上的。** `SIGRTMIN+n` 通过原始偏移量显示;库保留低几位供自身使用。
- **`comm` 是 16 字节。** 长进程名会被内核截断,而非 sigwire。

## 社区问题

**它会拖慢被跟踪的进程吗?**
没有明显的开销。tracepoint 程序是被动的;成本是在每次信号时进行有界环形缓冲区写入(以及每个系统调用退出时用于 EINTR 检测的几条指令),如果用户空间落后,环形缓冲区会丢弃而不是阻塞。

**它会显示针对在我启动时已经运行的进程的信号吗?**
会。从 sigwire 附加的那一刻起,tracepoint 为每个信号触发,无论发送者或目标何时启动——没有遗漏的每个进程状态。

**它适用于任何进程,还是仅一个?**
主机上的任何进程,同时全部覆盖——发送者/目标区分栏可以区分它们。这是整个机器的信号流量,而非单个 pid。

**我可以导出 feed 吗?**
没有内建功能。`probes/sigwire.js` 中的 `RingBuf.subscribe` 回调保存了每个解码的记录,因此 JSON/HTTP/Kafka 接收器是那里的一条分支。要设置托管管道,[联系我们](https://yeet.cx/)。

## 从源代码构建```sh
make          # clang + bpftool → bin/probe.bpf.o ; esbuild → src/index.jsx
make bpf      # just the BPF object
make bundle   # just the JS bundle
make clean    # remove build artifacts

然后 yeet run . 会运行本地构建。make 运行两个独立的编译器:clang + bpftool 将 src/bpf/*.bpf.c 链接成可加载对象 bin/probe.bpf.o;esbuild 将 src/main.jsx 打包成 src/index.jsx,通过 tsconfig 的 paths 解析 @/(源根目录)和 #/(项目根目录)这两个构建时别名,并将 yeet:* 内置模块保留为外部依赖。两个编译器都来自供应商提供的静态工具链,因此构建过程不需要系统 C/BPF 工具链,也不需要 node/npm。生成的 vmlinux.h、src/index.jsx 和 bin/*.bpf.o 是构建产物。

由于别名仅在构建时有效,运行时通过 import.meta.dirname 而非别名来定位 BPF 对象。参见 AGENTS.md(即 CLAUDE.md)了解 yeet 仪表板编写指南。

许可证

双许可证 BSD/GPL。BPF 程序在 src/bpf/sigwire.bpf.c 中声明了 char LICENSE[] SEC("license") = "Dual BSD/GPL",内核要求其使用的辅助函数必须包含此声明。


基于 yeet 构建,这是一个用于在 Linux 上编写 eBPF 程序的 JS 运行时。加入我们的 Discord。

下载工具
严重性信号颜色
致命SIGKILL热红
致命(生成 core 文件)SEGV BUS ABRT ILL FPE TRAP SYS QUIT红色
终止TERM INT HUP PIPE ALRM …琥珀色
作业控制STOP TSTP TTIN TTOU黄色
继续CONT绿色
用户USR1 USR2青色
实时SIGRTMIN+n紫色
内务CHLD URG WINCH …灰色