从一个真实场景说起
想象你是一名渗透测试工程师,客户告诉你:
"我们公司的服务器最近非常卡,安全扫描也跑不动了,能帮我们看看吗?"
你连上服务器一看:CPU 使用率 100%,内存几乎耗尽,硬盘 I/O 飙升。这时候你需要判断:
这是正常的业务负载?
还是服务器被植入了挖矿木马?
要做出正确判断,你必须理解计算机硬件是怎么工作的。CPU 为什么会被占满?内存和硬盘有什么区别?数据是怎么在这些硬件之间流动的?搞清楚这些问题,是你分析一切安全事件的起点。
核心硬件一览
一台计算机的核心硬件可以类比为一个工厂:
打个比方:工人(CPU)从仓库(硬盘)里把原材料搬到工作台(内存)上,在工作台上加工处理,处理完再放回仓库。工人干活的速度取决于他自己的能力(主频),而工作台的大小(内存容量)决定了他能同时处理多少东西。如果工作台太小,工人就得频繁跑仓库,效率自然就低了。
CPU:计算机的大脑
CPU(Central Processing Unit)是计算机的核心,所有程序最终都要由 CPU 来执行。你需要了解它的几个关键参数:
CPU 干活的流程其实很简单,就是不断重复四个步骤:
取指(Fetch)→ 解码(Decode)→ 执行(Execute)→ 写回(Write Back)
↑ |
└────────────────────────────────────────────────────┘
不断循环
每一个你运行的程序——无论是打开浏览器、执行 nmap 扫描、还是运行漏洞利用脚本——最终都被拆解成一条条指令,按这个流程被 CPU 处理。
2018 年曝光的 Meltdown 和 Spectre 漏洞是 CPU 级别的安全漏洞。它们利用了 CPU 的"推测执行"(Speculative Execution)机制,允许攻击者读取本不应该访问的内存数据。这类硬件层面的漏洞影响面极广,且几乎无法通过软件完全修复——只能通过微码更新和操作系统补丁来缓解。这也说明了一件事:不只是软件会有漏洞,硬件也会有。
内存:高速的临时工作区
内存(RAM, Random Access Memory)是 CPU 和硬盘之间的"桥梁"。为什么需要内存?因为硬盘太慢了。到底慢多少?看这个对比你就明白了:
看到差距了吧?CPU 缓存和机械硬盘之间的速度差了将近一千万倍。这就是为什么内存必须存在——它充当了一个"中转站",让 CPU 不用每次都跑到"外地仓库"去取东西。
内存有两个重要特点:
易失性:断电后数据消失(这就是为什么未保存的文件会丢失)
随机访问:可以直接访问任意地址的数据,不需要按顺序读取
内存取证(Memory Forensics)是数字取证的重要分支。很多恶意软件(如 Cobalt Strike 的 Beacon)采用"无文件攻击"——只在内存中运行,不写入硬盘,以此逃避传统杀毒软件的检测。使用 Volatility 等工具对内存进行分析,可以发现这些隐藏的恶意进程。换句话说,有些攻击痕迹只存在于内存中,硬盘上什么都找不到。
硬盘:永久的数据仓库
硬盘分为两大类:
在数据恢复和取证场景中,HDD 和 SSD 的行为完全不同。HDD 上"删除"的文件其实只是标记了空间可用,数据仍然存在,可以被恢复。而 SSD 由于 TRIM 机制,删除的数据可能很快被彻底擦除,增加了取证难度。所以做取证的时候,拿到的是 HDD 还是 SSD,处理策略是完全不同的。
冯诺依曼体系结构
讲完了各个硬件,我们来看看它们是怎么协作的。现代计算机几乎都遵循 冯诺依曼体系结构(Von Neumann Architecture),由数学家约翰·冯·诺依曼于 1945 年提出。
它的核心思想只有一句话:程序和数据都以二进制形式存储在内存中,CPU 从内存中取出指令并执行。
┌──────────────────────────────────────────────┐
│ CPU │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ 控制器(CU) │ │ 算术逻辑单元(ALU) │ │
│ │ 指挥调度中心 │ │ 执行计算和比较 │ │
│ └──────┬───────┘ └────────┬─────────┘ │
│ │ ┌───────────┐ │ │
│ └─────┤ 寄存器组 ├───┘ │
│ │ 最快的存储 │ │
│ └─────┬─────┘ │
└─────────────────────┼────────────────────────┘
│ 数据总线 / 地址总线 / 控制总线
│
┌──────▼──────┐
│ 内存(RAM) │
│ 存放程序和数据 │
└──────┬──────┘
│
┌──────▼──────┐
│ 输入/输出设备 │
│ 键盘/显示器/ │
│ 硬盘/网卡... │
└─────────────┘
冯诺依曼体系的五大组成部分:
运算器(ALU): 执行算术和逻辑运算
我们可以把它想象成工人,只负责干活:算加法、比较大小,自己本身是不会思考下一步要干什么,别人叫它算什么,它才算。
控制器(CU): 从内存取指令、解码、控制执行流程
把它想成工厂总指挥(老板),老板不用干体力活,工作只有两件事,一是去仓库拿纸条(指令),然后老板读懂纸条的命令,开始指挥工人干活。
存储器【内存ARM】: 存储程序和数据
把它想象成工厂的大仓库一般仓库是有归类的,但是这里的仓库没有,两类纸条(指令与数据)全部都是混堆在一起。
输入设备: 键盘、鼠标、网卡(接收数据包)等
输出设备: 显示器、打印机、网卡(发送数据包)等
这里有一个非常重要的安全问题需要你注意:冯诺依曼体系最大的特点是"存储程序"——程序(指令)和数据在同一个内存空间中。这个设计简洁高效,但也意味着:如果攻击者能够将恶意代码写入数据区域,并让 CPU 将其当作指令执行,就形成了缓冲区溢出攻击——这是二进制安全领域最经典的攻击手法之一。
打个比方:假设你有一个笔记本,前半部分记录的是"待办事项"(指令),后半部分记录的是"电话号码"(数据)。如果有人在你的电话号码区域偷偷写了一条"给张三转账一万元",而你不小心把它当成待办事项执行了——这就是缓冲区溢出的本质。
漏洞根源(冯·诺依曼核心缺陷)
一、漏洞根源
内存物理上不分指令区、数据区,全部混存。CPU只认二进制,无法区分数据和指令,遇到二进制一律执行。软件仅逻辑分区,无硬件隔离,这是溢出漏洞的根本成因。
二、漏洞成因
程序员未做输入长度校验,缓冲区空间固定有限,超长输入会越界覆盖相邻内存数据。
栈内存固定排布(无空隙):缓冲区 → 紧邻返回地址(书签)
三、攻击完整流程
缓冲区仅8字节,黑客传入20字节构造数据
前8字节:填满缓冲区,存放恶意机器码(shellcode)
后12字节(溢出):覆盖紧邻的返回地址,篡改为缓冲区自身地址
函数执行结束,CPU硬件强制读取返回地址跳转
CPU跳转到数据区缓冲区,将恶意数据当作指令执行,拿下程序控制权(可反弹Shell、提权、读数据)
四、栈帧层次和内存拷贝的写入起点
栈的层次(栈帧层级:第 1 层 main,第 2 层函数 A,第 3 层函数 B…… 第 5 层函数 E)
每调用一个函数,就新增一层栈帧。
每一层栈帧里面,都有属于这一层自己的缓冲区 buf、属于这一层自己的返回地址(本层的书签)。第 5 层 = 当前正在运行的这个子函数。
第 5 层栈帧内部:[局部buf缓冲区] 紧紧挨着 [第5层自己的返回地址]
这个第 5 层的返回地址,记录的是:干完第 5 层,回到第 4 层代码的位置。
拷贝写入的起点:当黑客的数据,只写入当前第 5 层栈帧里的 buf 缓冲区,就攻击不到其他层栈帧。
因为payload 写入,只从当前函数的 buf 缓冲区地址开始向后写,只能破坏本层(第 5 层)栈帧内后面相邻内存,改不到上层(1‑4 层)栈帧的数据
模拟调用链
main(第1层) → func1(第2层) → func2(第3层) → func3(第4层) → input_name(第5层,漏洞函数)
原本
input_name是第 5 层栈帧:里面有 buf 缓冲区(8 字节),紧跟着第 5 层的返回地址。这个第 5 层返回地址本来写的是:
input_name干完活,回到第 4 层 func3 里面继续执行。
但当我们攻击中构造超长输入写入第 5 层 buf:
填满第 5 层 buf 缓冲区,放入
shellcode恶意机器码。溢出区域,只覆盖第 5 层自己的返回地址,把它改掉,根本不会跑到第
4、3、2、1层栈帧去改写上层内存,做不到。篡改后,第 5 层的书签不再写 “回到第 4 层”,而是写:跳转到本层 buf 缓冲区地址。
引爆过程input_name(第 5 层函数)执行完毕,CPU 硬件会处理 ret:读取第 5 层栈帧上被篡改过的返回地址,接着直接跳转到第 5 层 buf 缓冲区,执行 shellcode 恶意代码。
重点:跳转不是回到第 4、3、2、1 层函数,而是ret 指令读取被篡改的地址,直接跳去缓冲区,直接跑恶意机器码,上层栈帧(1‑4 层)完全不动,根本不需碰不到,除非是正常的输入函数。
五、所有疑惑
疑问 1:为什么溢出刚好覆盖返回地址?
栈内存是编译器固定排布、物理连续无空隙的:缓冲区后面紧紧挨着返回地址。写超了不会排队、不会缓存、不会放末尾,只会直接覆盖隔壁内存。
疑问 2:为什么 CPU 必须执行被篡改的地址?
返回地址是 CPU 硬件强制跳转规则。函数结束一定会读书签跳转,不是可选逻辑,是底层机制,无法跳过。
疑问 3:覆盖内存不会被发现吗?
栈是程序自己的内存,操作系统不检测程序内部数据修改。只要不访问非法内存,程序不崩溃,系统就不会报警。黑客精准篡改关键地址,不会直接崩程序,所以很难被发现。
疑问 4:和反弹 shell(bash -c)的关系?
缓冲区溢出拿到 CPU 控制权后,执行 shellcode 机器码,底层调用系统函数,间接实现 bash -c 反弹 shell 的效果。bash -c 是人类命令,溢出执行的是二进制机器码,最终效果一致。
数据的二进制表示
计算机内部一切数据都以 二进制(0 和 1)表示。这个你可能早就听说过,但作为安全从业者,你需要对进制转换非常熟练,因为你每天都会跟它们打交道。
1、基础单位
bit(比特,b): 最小单位,只能存
0或者1,就像一的电灯,只有开/关Byte(字节,B): 1字节 =8 个bit,相当于8 盏电灯排成一组。
1 字节 8个 0/1 组合,一共 28=25628=256 种状态,数字范围:0~255
重点记住两个考试高频:
1 字节 (8bit):0‑255
2 字节 (16bit):0‑65535(端口号!)2.如何换算
核心:
二进制只有0、1,并且逢 2 进 1。
十进制:0-9,逢 10 进 1
权位
二进制每一位都有权重,从右边开始数,从 0 开始次方
二进制位: 第7位 第6位 第5位 第4位 第3位 第2位 第1位 第0位
权重(2ⁿ): 128 64 32 16 8 4 2 1
8 位二进制(1 字节)权重固定:128,64,32,16,8,4,2,1二进制 变 十进制:把是 1 的位置权重全部相加
示例 1:00001010
0 0 0 0 1 0 1 0
权重: 128 64 32 16 8 4 2 1
为 1 的位是 8 和 2 那么: 8 + 2 = 10 相当于 二进制 00001010 = 十进制 10十进制 变 二进制:除 2 取余,倒着写
例子:把十进制 转二进制
10 ÷2 =5 余 0
5 ÷2 =2 余 1
2 ÷2 =1 余 0
1 ÷2 =0 余 1
余数从下往上拿:1010
补成完整 1 字节 8 位:00001010十六进制和二进制换算
二进制对人类来说太长了,一个字节要写 8 位数字。十六进制是二进制的"缩写形式":每 4 位二进制恰好对应 1 位十六进制
实例:
1 个十六进制 = 4 个二进制位 = 0.5 字节
2 个十六进制 = 8 个二进制位 = 1 字节
0:0000 1:0001 2:0010 3:0011
4:0100 5:0101 6:0110 7:0111
8:1000 9:1001 A:1010 B:1011
C:1100 D:1101 E:1110 F:1111
1 字节 = 8bit = 2 位十六进制
1111 1111 拆两半:1111 1111 → F F → 0xFF
0000 1010 拆两半:0000 1010 →0 A → 0x0A十六进制在安全工作中的应用
在安全工作中,你会在以下场景频繁使用十六进制:
分析网络数据包: Wireshark 默认用十六进制显示原始数据
查看内存和文件内容:
hexdump、xxd等工具输出的都是十六进制编写/阅读 Shellcode: Shellcode 用
\x41\x42\x43(即 ABC 的 ASCII 码)表示MAC 地址:
AA:BB:CC:DD:EE:FF,每段是 1 字节的十六进制
动手实验: 打开 Windows 计算器(Win+R → calc),切换到"程序员"模式,将十进制数
3389(Windows 远程桌面端口)转换为十六进制和二进制。你会得到0x0D3D和0000 1101 0011 1101。记住这个端口号,以后你会经常跟它打交道。
3.结合前面的重点
8bit(1 字节):最大 2⁸‑1 =255,范围 0~255 → 0x00 ~ 0xFF
16bit(2 字节,端口):最大 2¹⁶‑1 =65535,范围 0~65535 → 0x0000 ~0xFFFF
为什么安全从业者需要掌握进制转换?因为你几乎每天都会碰到下面这些场景,而它们的底层逻辑都建立在"用固定数量的二进制位来表示数据"这个基本原则之上。
场景一:端口号为什么是 0-65535?
你一定见过"80 端口""443 端口""3389 端口"这些说法。但为什么端口号的上限是 65535,不是 100000 或者 99999?
答案藏在二进制里。计算机在网络通信时,需要用一段固定长度的二进制数来记录端口号。TCP/UDP 协议规定:端口号占 2 个字节(Byte),即 16 个二进制位(bit)。
我们来算一下 16 个二进制位最多能表示多大的数:
1 个二进制位能表示: 0 或 1 → 2 种可能(2^1)
2 个二进制位能表示: 00, 01, 10, 11 → 4 种可能(2^2)
3 个二进制位能表示: 000 ~ 111 → 8 种可能(2^3)
...
8 个二进制位(1字节)能表示: → 256 种可能(2^8),范围 0 ~ 255
16 个二进制位(2字节)能表示: → 65536 种可能(2^16),范围 0 ~ 65535所以端口号的范围是 0 到 65535——不是人为规定的"好记的数字",而是 2 个字节能表示的最大无符号整数。这就是为什么你永远不会见到端口号 70000。
安全视角: 在渗透测试中进行端口扫描时,Nmap 默认只扫描常见的 1000 个端口。如果要做全端口扫描(
nmap -p 0-65535),你就需要理解这个上限的来源——它不是随意设定的,而是协议层面的硬性约束。
场景二:IP 地址的二进制本质
我们平时看到的 IP 地址 192.168.1.1 是"点分十进制"写法——它只是方便人类阅读的表示方式。计算机实际存储和处理的是一个 32 位(4 字节)的二进制数。
把每段十进制数转换为 8 位二进制:
192 = 1100 0000
168 = 1010 1000
1 = 0000 0001
1 = 0000 0001
192.168.1.1 的完整二进制:
11000000 . 10101000 . 00000001 . 00000001为什么每段的范围是 0-255?因为每段占 1 个字节(8 位),而 8 位二进制的最大值 1111 1111 = 十进制 255。所以你永远不会看到 192.168.1.300 这样的 IP 地址——300 超出了 1 个字节能表示的范围。
安全视角: 理解 IP 地址的二进制本质,是后面学习子网划分、CIDR 表示法、以及内网渗透中网段判断的基础。
场景三:子网掩码与 CIDR
子网掩码 255.255.255.0 转换为二进制后,规律一目了然:
255.255.255.0
= 11111111 . 11111111 . 11111111 . 00000000
←——— 24个1 ———→←— 8个0 —→前面连续的 1 表示"网络部分",后面连续的 0 表示"主机部分"。因为有 24 个 1,所以简写为 /24。
这意味着什么?主机部分有 8 位,所以这个子网最多能容纳 2^8 - 2 = 254 台主机(减去的 2 个是网络地址和广播地址)。
/24 → 主机位 8 位 → 最多 254 台主机
/16 → 主机位 16 位 → 最多 65534 台主机
/25 → 主机位 7 位 → 最多 126 台主机如果不理解二进制,这些数字就像"天书";理解了二进制,它们都是简单的 2 的幂次运算。
讲完了硬件层面的知识,接下来我们往上走一层,看看操作系统是怎么管理这些硬件的。
一、操作系统是什么
类比:硬件 = 一栋大楼;操作系统 = 物业公司
电脑硬件(CPU、内存、硬盘、网卡)就是大楼的钢筋水泥。
浏览器、Nmap、微信这些软件 = 大楼里的住户。
住户(软件)不能直接去操作硬件:不能自己指挥 CPU、自己读写硬盘。全部交给物业(操作系统)干活。
物业(操作系统)4 件核心工作:
管理硬件资源:分配 CPU 时间、分配内存、管理网卡显卡驱动。好比物业分配会议室、停车位。
提供系统调用(前台服务):软件想读文件、联网,跟操作系统说一声就行,不用懂硬件底层。
安全隔离:A 软件不能随便偷看 B 软件的内存;不同用户互不干扰。
管理文件:把硬盘一堆 01 二进制整理成你看得见的文件夹、文档。
主流操作系统(网安要掌握)
Windows:企业内网、域环境最多,内网渗透主要打它。
Linux:绝大多数网站服务器;Kali 就是 Linux,渗透工具基本都跑这上面。
macOS:开发人员、安全研究员在用,源自 Unix。
安卓 /iOS:手机移动安全测试。
二、进程与线程
非常重要,恶意软件、提权、入侵检测全靠它
程序:硬盘上存的静态文件(比如 nmap.exe,躺在硬盘,没运行)
进程:程序跑起来之后的实例。打开 Nmap,就生成一个 Nmap 进程。
每个进程拥有自己独立的内存空间。A 进程看不到 B 进程内存,互相隔离。
线程:进程内部干活的小工人。
一个进程可以开好几个线程,全部共享这个进程的内存。
类比:
进程 = 独立车间;线程 = 车间里面干活的工人
车间 A(浏览器)里面 3 个工人(线程),共享车间全部物资;
车间 B(Nmap)里面 2 个工人。
车间 A 和车间 B 互相隔开,不能直接串门。
网安为什么要学这个:
入侵排查:服务器中木马,第一件事看有哪些异常进程。
恶意软件:进程注入:病毒不新建一个奇怪程序,偷偷把恶意代码塞到正常进程里面跑(例如 svchost.exe)。任务管理器看进程名完全正常,但是已经中毒。
👉所以排查不能只看进程名字,要看:命令行、父进程、网络连接。
提权漏洞:利用不同进程权限不一样,低权限进程想办法拿到高权限。
三、文件系统
硬盘本身只是存一堆 0 和 1,看不懂文档、文件夹。
文件系统就是一套规则:规定文件怎么存、怎么找、谁有权读写文件。
简单理解:FAT32 就像完全开放的储物柜,谁都能打开拿东西;NTFS/ext4 相当于柜子带锁,可以设置谁能看、谁不能改。
四、用户和权限管理
电脑账户分等级:
最高管理员:Windows 叫
Administrator;Linux 叫root。想干什么都能干,删系统文件、改配置、拿全部数据。普通用户:权限有限,很多操作被拦截。
服务账号:专门用来跑网站、数据库服务的账号,不是给人登录用。
最小权限原则(安全黄金规则)
程序 / 用户,只给完成工作刚刚好的权限,多余权限一律不给
例子:
Web 网站只需要读取网页文件,不需要 root 最高权限。
普通员工账号,不该给管理员权限。
为什么对渗透这么关键:
很多漏洞危害变大,就是违背最小权限。
如果网站程序以 root 最高权限运行,一旦网站被攻破,攻击者直接拿到服务器最高控制权。
如果网站只用普通账号运行,就算网站被攻破,黑客还要再找漏洞做提权,防守方就多了一层防护。
以上就是计算机组成原理。