From 29e0c490af80f1271b0a080649295f3c070cd039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=BE=E5=B3=B6=E9=A3=8E=E8=B5=B7=E6=99=82?= Date: Thu, 25 Sep 2025 04:01:20 +0800 Subject: [PATCH] Add files via upload --- Chapter22/22-1.md | 33 ++++++++++++++++ Chapter22/22-2.md | 21 ++++++++++ Chapter22/22-3.md | 32 +++++++++++++++ Chapter22/22-4.md | 36 +++++++++++++++++ Chapter22/22-5.md | 96 +++++++++++++++++++++++++++++++++++++++++++++ Chapter22/22-6.md | 52 ++++++++++++++++++++++++ Chapter22/22-7.md | 27 +++++++++++++ Chapter22/README.md | 19 +++++++++ 8 files changed, 316 insertions(+) create mode 100644 Chapter22/22-1.md create mode 100644 Chapter22/22-2.md create mode 100644 Chapter22/22-3.md create mode 100644 Chapter22/22-4.md create mode 100644 Chapter22/22-5.md create mode 100644 Chapter22/22-6.md create mode 100644 Chapter22/22-7.md diff --git a/Chapter22/22-1.md b/Chapter22/22-1.md new file mode 100644 index 0000000..a0ac1ff --- /dev/null +++ b/Chapter22/22-1.md @@ -0,0 +1,33 @@ +### 进程和线程内存空间的关系 + +**进程的内存空间** + +一个**进程**可以看作是一个正在运行的程序实例。操作系统为每个进程分配独立的、私有的内存空间,这通常被称为**虚拟地址空间**。这个独立的地址空间主要包括以下几个关键区域: + +- **代码段**:存放可执行文件的机器指令(也就是程序的代码)。这部分通常是只读的,以防止程序在运行时修改自身代码 +- **数据段**:存放已初始化的全局变量和静态变量 +- **BSS 段**:存放未初始化的全局变量和静态变量 +- **堆**:用于动态内存分配。程序在运行时,可以随时从堆中申请和释放内存 +- **栈**:用于存放局部变量、函数参数和返回地址。栈是自动管理的,遵循先进后出(LIFO)的原则 + +**关键点**:每个进程都有自己独立的虚拟地址空间。这意味着,一个进程无法直接访问另一个进程的内存,除非使用进程间通信(IPC)机制。这种隔离性是操作系统的核心安全机制,可以防止一个进程的错误影响到其他进程,从而保证系统的稳定性 + +**线程的内存空间** + +一个**线程**是进程内的一个执行单元,有时也被称为“轻量级进程”。与进程不同的是,**同一个进程内的所有线程共享该进程的内存空间** + +具体来说,这些线程共享: + +- **代码段**:所有线程执行的是同一份程序代码 +- **数据段**:所有线程都可以访问和修改同一个进程的全局变量和静态变量 +- **堆**:所有线程都可以从同一个堆中申请和释放动态内存 + +但是,每个线程都有自己**独立的**私有部分: + +- **栈**:每个线程都有自己的私有栈,用于存放它自己的局部变量和函数调用信息。这是为了确保每个线程在执行函数时,不会影响到其他线程的执行上下文 +- **寄存器**:每个线程都有自己的寄存器集合,用来保存其执行状态 + +可以把**进程**想象成一个**拥有独立房子的住户**,这个房子里有独立的厨房、客厅和卧室(代表私有的内存空间)。而**线程**则可以想象成**房子里的不同家庭成员** + +- **进程**:拥有独立的房子(**独立的地址空间**) +- **线程**:是房子里的家庭成员。他们共享房子里的公共区域,比如**客厅(堆)**、**厨房(数据段)**,但每个人有自己的**卧室(栈)和衣柜(寄存器)** \ No newline at end of file diff --git a/Chapter22/22-2.md b/Chapter22/22-2.md new file mode 100644 index 0000000..98e6deb --- /dev/null +++ b/Chapter22/22-2.md @@ -0,0 +1,21 @@ +### 介绍下父子进程 + +**父子进程的创建** + +父子进程的关系是通过一个特殊的系统调用——**`fork()`** 来创建的 + +1. 当一个进程(我们称之为**父进程**)调用 `fork()` 时,操作系统会复制父进程的几乎所有信息,包括代码、数据、堆、栈等,来创建一个新的进程,也就是**子进程** +2. `fork()` 系统调用有一个关键的特点:在父进程中,它会返回新创建的子进程的 **PID(进程ID)**;而在子进程中,它会返回 **0**。这使得程序可以根据返回值来判断自己是父进程还是子进程,并执行不同的代码路径 + +**父子进程的资源关系** + +尽管子进程是父进程的副本,但在资源管理上,它们之间存在一些重要的区别: + +- **独立的内存空间**:在创建时,子进程会获得一个与父进程几乎相同的独立内存副本。这意味着,父进程和子进程对各自内存的修改不会互相影响。这遵循了 **写时复制(Copy-on-Write, CoW)** 的机制,即最初它们共享相同的内存页,只有当任一进程试图修改该内存页时,才会真正创建一个新的副本 +- **独立的 PID**:每个进程都有一个唯一的 PID,子进程会获得一个新的、独立的 PID +- **共享资源**:父子进程会共享一些只读资源,例如程序代码段。此外,它们还会共享打开的文件描述符。这意味着,如果在 `fork()` 前父进程打开了一个文件,那么子进程也会继承这个文件描述符,可以继续读写这个文件 + +**父子进程的生命周期** + +- **正常终止**:如果父进程或子进程正常执行完毕,它们会退出。当子进程终止时,它会变成一个**僵尸进程(Zombie Process)**,直到它的父进程通过 `wait()` 或 `waitpid()` 系统调用来“收尸”,获取它的退出状态,然后这个僵尸进程才会被操作系统彻底清理 +- **孤儿进程**:如果父进程在子进程之前终止,子进程就会成为一个**孤儿进程(Orphan Process)**。在这种情况下,操作系统的 **`init` 进程(PID 1)** 会收养这个孤儿进程,成为它的新父进程。`init` 进程会负责清理这些孤儿进程,防止它们变成永久的僵尸进程 \ No newline at end of file diff --git a/Chapter22/22-3.md b/Chapter22/22-3.md new file mode 100644 index 0000000..b52ad46 --- /dev/null +++ b/Chapter22/22-3.md @@ -0,0 +1,32 @@ +### 孤儿进程和僵尸进程区别 + +**僵尸进程** + +**僵尸进程**是已经**终止**(执行完毕或被杀死)但其父进程尚未**收集**(`wait()` 或 `waitpid()` 系统调用)其退出状态的进程 + +- **产生原因**:当一个子进程终止时,它会向操作系统发送一个信号,表示自己已完成任务。操作系统会释放该进程几乎所有的资源,包括内存和文件描述符。然而,它的进程描述符(PCB,Process Control Block)仍然保留在内存中,以便父进程能够读取它的退出状态(例如,是否成功执行、退出码是多少)。如果父进程没有及时调用 `wait()` 或 `waitpid()` 来获取这些信息并释放子进程的 PCB,子进程就会一直处于“僵尸”状态 +- **特点**: + - 它**不占用**内存空间 + - 它**会占用**一个 PID,因为 PCB 还没有被回收 + - 由于 PID 是有限的,大量的僵尸进程可能会导致系统没有可用的 PID,从而无法创建新的进程 +- **如何识别**:在 `ps` 或 `top` 命令的输出中,僵尸进程的状态通常显示为 `` 或 `Z` +- **处理方法**:唯一能清理僵尸进程的方法是**杀死它的父进程**。当父进程被杀死后,这个僵尸进程就会变成一个孤儿进程,并被 `init` 进程(PID 1)收养,`init` 进程会负责清理它。 + +**孤儿进程** + +**孤儿进程**是指**正在运行**但其父进程已经**终止**的进程 + +- **产生原因**:当父进程在子进程之前退出,子进程就成了“孤儿” +- **特点**: + - 它**仍然在运行**,只是失去了它的原始父进程 + - 它**不会**成为系统的负担,因为它会自动被操作系统中最特殊的进程——`init` 进程(PID 1)收养 +- **如何识别**:在 `ps` 命令的输出中,你可以看到它的父进程 ID(PPID)变成了 `1` +- **处理方法**:孤儿进程会被 `init` 进程**收养**。`init` 进程会像对待自己的子进程一样,在它最终终止时调用 `wait()` 来收集其退出状态,从而防止它变成一个僵尸进程 + +| 特性 | 僵尸进程(Zombie Process) | 孤儿进程(Orphan Process) | +| -------- | --------------------------------------- | ------------------------------------------ | +| 状态 | 已终止,但其进程描述符未被父进程回收。 | 正在运行,但其父进程已终止。 | +| 产生原因 | 父进程没有调用 wait() 或 waitpid()。 | 父进程在子进程之前退出。 | +| 系统影响 | 占用 PID,大量存在会导致 PID 资源耗尽。 | 通常无害,会被 init 进程收养。 | +| 处理方式 | 杀死其父进程。 | 由 init 进程自动收养并管理,无需人工干预。 | +| ps 状态 | Z 或 | 运行中,但其 PPID(父进程 ID)为 1。 | \ No newline at end of file diff --git a/Chapter22/22-4.md b/Chapter22/22-4.md new file mode 100644 index 0000000..4847153 --- /dev/null +++ b/Chapter22/22-4.md @@ -0,0 +1,36 @@ +### Kill 一个进程的时候都发生了那些事情,从父子进程角度讲 + +**1. 信号发送与接收** + +当你执行 `kill ` 时,操作系统内核会向指定的进程(通常是子进程)发送 `SIGTERM` 信号 + +- **如果目标进程是子进程**:父进程并没有直接参与这个过程。信号是由内核发送给目标进程的,由内核负责后续的调度和处理 +- **如果目标进程是父进程**:同样,信号由内核直接发送。但父进程的死亡会对其子进程产生连锁反应 + +**2. 进程对信号的响应** + +这是最关键的一步,也是 `SIGTERM` 和 `SIGKILL` 最大的区别所在 + +- **接收 `SIGTERM`(友好终止)**: + - 这是一个“软性”的终止请求,目标进程可以**捕获(handle)**或**忽略(ignore)**这个信号 + - 如果目标进程有信号处理程序,它会执行相应的清理工作,例如: + - 释放占用的内存、文件描述符等资源 + - 保存当前的工作状态 + - 优雅地关闭网络连接 + - 清理完成后,进程会正常退出 + - **父子进程关系**:如果被 `kill` 的是父进程,并且父进程捕获了 `SIGTERM` 并执行了清理,它可能会在退出前向它的子进程发送信号(例如 `SIGTERM`),或者等待子进程先退出。但如果父进程直接退出,其子进程会变成**孤儿进程**,被 `init` 进程收养 +- **接收 `SIGKILL`(强制终止)**: + - 这是一个“硬性”的终止请求,目标进程**无法捕获、忽略或阻止**这个信号 + - 操作系统内核会直接终止这个进程,**不会**给它任何机会执行清理工作 + - 这种方式非常粗暴,可能导致数据丢失、资源泄露(例如,没有关闭的文件、没有释放的锁),所以通常不建议作为首选 + - **父子进程关系**: + - 如果被 `kill -9` 的是**子进程**,它会立即被内核终止。子进程会进入**僵尸状态**,其父进程需要调用 `wait()` 来收集它的退出状态,否则它会一直占用一个 PID + - 如果被 `kill -9` 的是**父进程**,父进程会立即被内核强制终止。其所有子进程都会立刻变成**孤儿进程**,并被 `init` 进程(PID 1)收养。`init` 进程会负责等待它们终止,并清理它们的僵尸状态,避免系统资源泄露 + +**3. 进程状态转换与资源回收** + +无论以何种方式终止,进程都会经历以下状态转换: + +- **从运行状态到终止状态**:当一个进程终止后,它的所有资源(如内存页、文件描述符等)都会被释放 +- **成为僵尸进程**:一个进程终止后,它的进程描述符(PCB)仍然保留在内存中,记录其退出状态,等待父进程来“收尸”。此时,该进程就进入了僵尸状态 +- **父进程的责任**:为了避免子进程成为僵尸,父进程的责任是调用 `wait()` 或 `waitpid()`。一旦调用,内核就会将僵尸子进程的 PCB 彻底移除,释放其占用的 PID,完成最终的清理工作 \ No newline at end of file diff --git a/Chapter22/22-5.md b/Chapter22/22-5.md new file mode 100644 index 0000000..a8b7dfd --- /dev/null +++ b/Chapter22/22-5.md @@ -0,0 +1,96 @@ +### Linux 开机自启动方式 + +**系统级别的自启动方式** + +这些是系统在引导过程中自动执行的脚本或服务,通常用于启动核心服务和守护进程 + +**1. Systemd** + +Systemd 是现代 Linux 发行版(如 Ubuntu 16.04+、CentOS 7+、Debian 8+)中最主流的启动管理器。它使用 **`.service`** 单元文件来定义服务,这些文件通常存放在以下目录: + +- `/etc/systemd/system/`:管理员创建或修改的服务文件 +- `/usr/lib/systemd/system/`:软件包安装的服务文件,不建议直接修改 + +恶意程序可能会在这些目录中创建或修改 `.service` 文件,将自己伪装成一个合法的服务 + +**如何检查:** + +- `systemctl list-unit-files --type=service`:列出所有服务的单元文件 +- `systemctl status `:检查特定服务的状态 +- `systemctl cat `:查看服务文件的具体内容,包括执行命令 + +**2. Init 脚本** + +在较旧的 Linux 发行版中(如 CentOS 6、Ubuntu 14.04),系统使用 Init 脚本来管理启动 + +- **SysVinit**:脚本存放在 `/etc/init.d/` 目录,通过 `rcX.d` 目录(X代表运行级别)的软链接来控制服务的启动顺序 +- **Upstart**:配置文件存放在 `/etc/init/` 目录 + +恶意程序可能会在 `/etc/init.d/` 中添加新脚本,或在 `/etc/rcX.d/` 中创建软链接,从而在系统启动时被执行 + +**如何检查:** + +- `ls -l /etc/init.d/`:查看所有 Init 脚本 +- `ls -l /etc/rc?.d/`:查看不同运行级别下的软链接 + +**用户级别的自启动方式** + +这些方式通常只在特定用户登录后才会被执行,常用于启动桌面环境下的应用程序 + +**1. Cron 定时任务** + +Cron 用于在指定的时间自动执行任务,也可以被配置为在系统启动时执行 + +- `/etc/crontab`:系统级别的 Cron 文件,可用于设置在系统启动时执行的脚本(使用 `@reboot` 关键字) +- `/etc/cron.d/`:存放独立的系统级 Cron 文件 +- `/var/spool/cron/crontabs/`:用户级别的 Cron 文件 + +恶意程序可能会利用 `@reboot` 字段,将自己添加到这些文件中,从而实现开机自启动 + +**如何检查:** + +- `cat /etc/crontab`:查看系统 Cron 文件 +- `ls -l /etc/cron.d/`:查看独立 Cron 文件 +- `crontab -l`:查看当前用户的 Cron 任务 +- `crontab -l -u `:查看特定用户的 Cron 任务。 + +**2. 用户配置文件** + +许多 Shell 和桌面环境都有自己的启动文件 + +- `~/.bashrc`、`~/.bash_profile`、`~/.profile`:这些文件在用户登录时会被 Shell 加载,恶意代码可以被注入其中 +- `~/.config/autostart/`:桌面环境(如 GNOME、KDE)下的自启动目录。这个目录下的 `.desktop` 文件可以指定一个程序在用户登录后自动运行 + +**如何检查:** + +- `cat ~/.bashrc`、`~/.bash_profile` 等:检查可疑命令 +- `ls -l ~/.config/autostart/`:查看可疑的 `.desktop` 文件 + +**其他隐蔽的自启动方式** + +除了上述常见方式,恶意程序还可能采用更隐蔽的手段。 + +**1. SUID/SGID 文件** + +虽然不是直接的自启动方式,但拥有 SUID 或 SGID 权限的程序可以在不询问用户密码的情况下以高权限运行,这对于持久化攻击非常有用。攻击者可以利用这些程序在系统启动后被调用时,执行自己的恶意代码 + +**如何检查:** + +- `find / -type f -perm /4000 2>/dev/null`:查找所有 SUID 文件。 +- `find / -type f -perm /2000 2>/dev/null`:查找所有 SGID 文件 + +**2. SSH 密钥** + +攻击者可以修改 `~/.ssh/authorized_keys` 文件,添加自己的公钥,从而在无需密码的情况下远程登录。虽然不是开机自启动,但它能让攻击者在系统重启后仍能获得持续访问权限 + +**如何检查:** + +- `cat ~/.ssh/authorized_keys`:检查是否存在陌生的公钥 + +**3. 动态链接库** + +`LD_PRELOAD` 环境变量可以让攻击者在程序启动时预先加载一个恶意动态链接库(`.so` 文件),从而劫持合法程序的函数调用,实现代码注入。如果将 `LD_PRELOAD` 变量写入全局配置文件(如 `/etc/profile`),则会对所有用户生效 + +**如何检查:** + +- `cat /etc/profile`、`~/.bashrc` 等:检查 `LD_PRELOAD` 环境变量是否被设置 \ No newline at end of file diff --git a/Chapter22/22-6.md b/Chapter22/22-6.md new file mode 100644 index 0000000..9fd0232 --- /dev/null +++ b/Chapter22/22-6.md @@ -0,0 +1,52 @@ +### Linux 有哪些系统调用 + +**1. 进程管理相关系统调用** + +这些调用用于创建、销毁和管理进程 + +- `fork()`: 创建一个子进程,它是父进程的精确副本 +- `execve()`: 在当前进程中加载并执行一个新程序 +- `wait4()`: 暂停当前进程,等待子进程退出或停止 +- `exit()`: 终止当前进程并返回一个状态码。 +- `getpid()`: 获取当前进程的 ID。 + +**2. 文件和设备管理相关系统调用** + +这些调用是应用程序与文件系统交互的核心,包括文件的创建、读写和权限管理 + +- `open()`: 打开或创建一个文件,返回一个文件描述符 +- `read()`: 从文件描述符中读取数据 +- `write()`: 向文件描述符中写入数据 +- `close()`: 关闭一个文件描述符 +- `lseek()`: 移动文件读写指针的位置 +- `stat()`: 获取文件的状态信息,例如大小、权限和创建时间 +- `unlink()`: 删除一个文件 +- `ioctl()`: 用于设备特有的 I/O 操作 + +**3. 信息维护相关系统调用** + +这些调用用于获取或设置系统信息,如时间、用户信息和系统配置 + +- `gettimeofday()`: 获取当前时间和时区信息 +- `uname()`: 获取操作系统的名称和版本信息 +- `getuid()`: 获取当前用户的有效 ID +- `getgid()`: 获取当前用户的有效组 ID + +**4. 通信相关系统调用** + +这些调用主要用于进程间通信(IPC)和网络通信 + +- `pipe()`: 创建一个匿名管道,用于父子进程间的通信 +- `socket()`: 创建一个网络套接字 +- `connect()`: 连接到远程主机 +- `bind()`: 将套接字绑定到一个地址和端口 +- `listen()`: 监听来自客户端的连接请求 +- `accept()`: 接受一个客户端的连接 + +**5. 内存管理相关系统调用** + +这些调用用于分配、释放和管理进程的内存 + +- `brk()`: 改变数据段的结束地址 +- `mmap()`: 创建一个内存映射,用于在文件中或设备中进行内存操作 +- `munmap()`: 撤销 `mmap()` 创建的内存映射 \ No newline at end of file diff --git a/Chapter22/22-7.md b/Chapter22/22-7.md new file mode 100644 index 0000000..09e31f4 --- /dev/null +++ b/Chapter22/22-7.md @@ -0,0 +1,27 @@ +### 说说 Linux 下的 Syscall + +**什么是系统调用(Syscall)?** + +在 Linux(及其他类 Unix 操作系统)中,**系统调用**是用户空间程序(User-space program)与内核(Kernel)之间进行交互的唯一接口 + +你可以将内核想象成一个操作系统的“核心”,它负责管理和控制计算机的所有硬件资源,例如 CPU、内存、硬盘和网络。而我们日常使用的所有应用程序,比如浏览器、文本编辑器或命令行工具,都运行在**用户空间** + +为了确保系统的稳定和安全,用户空间的程序不能直接访问硬件。当一个程序需要做一些“特权”操作时,比如: + +- 读写文件 +- 创建或销毁进程 +- 分配内存 +- 发送网络数据包 +- 获取当前时间 + +它就必须通过一个**系统调用**来向内核发出请求。内核会检查这个请求是否合法,如果合法,就会代表用户程序执行这个操作 + +**系统调用的工作流程** + +一个典型的系统调用流程如下: + +1. **准备参数**:用户空间的程序将要传递给内核的参数(例如,打开文件时的文件名和权限)放入指定的通用寄存器中 +2. **设置系统调用号**:程序将一个唯一的**系统调用号**(Syscall Number)放入另一个特定寄存器(在 x86 架构中通常是 `EAX` 或 `RAX`)中。这个号码告诉内核,程序想要执行哪一个系统调用(比如 `open` 对应 `2`,`read` 对应 `3`) +3. **触发软中断**:程序执行一条特殊的**中断指令**(例如 `int 0x80` 在 32 位系统上,或者 `syscall` 在 64 位系统上)。这条指令会暂停用户程序的执行,并强制 CPU 将控制权从用户空间转移到内核空间 +4. **内核处理**:内核接收到中断后,会根据寄存器中的系统调用号,在系统调用表中查找并执行对应的内核函数 +5. **返回结果**:内核函数执行完毕后,会将结果(成功或失败的代码)放入一个寄存器中,并执行一条返回指令,将控制权和结果返回给用户空间的程序 \ No newline at end of file diff --git a/Chapter22/README.md b/Chapter22/README.md index 8b13789..9eecb4f 100644 --- a/Chapter22/README.md +++ b/Chapter22/README.md @@ -1 +1,20 @@ +# 网安面试题(涵盖护网、红队、逆向、二进制) +上万道安全面试题已经全部为您划分好,适用于网络安全所有岗位!!! + +HR:请问………… + +我:叽里咕噜说啥呢,看看八股文上写了没 + +(Summary.md 是目录噢!!) + +**🙏 特别感谢名单** + +在整理和完善本项目的过程中,以下朋友给予了宝贵的帮助与支持,在此表示诚挚的感谢!(排名不分先后) + +- **@用户名1** —— 提供了大量安全面试题方向的补充 +- **@用户名2** —— 纠正了多个问题的答案与表述 +- **@用户名3** —— 贡献了真实面试题经验分享 +- **@用户名4** —— 对内容结构与目录提出改进建议 + +如果您也愿意参与本项目,欢迎通过 **微信: XR3327026244** 投稿面试题或反馈问题,我们会在后续版本中加入您的名字