引言
CTF 的 Misc 方向是「什么都可能考」的分类:隐写、取证、编码、流量、压缩包、内存镜像,边界模糊但内核一致,都是在数据里找被人为藏起来的信息。它考的不是单点工具,而是对文件格式、编码层级与取证流程的系统性理解。
工程上的难点有三个。第一是格式即线索:同一段字节在不同容器里有完全不同的解释,PNG 的 IDAT 与 ZIP 的本地文件头可能只差几个字节的偏移,能不能一眼看出「文件头与扩展名不符」决定了后续分析是否走对方向。第二是层级嵌套:一个 flag 可能先 LSB 隐写进 PNG,再把 PNG 追加到 ZIP 尾部,整体再做一遍 base64,逐层剥离的顺序错了就白费功夫。第三是取证的可信度:真实取证要求哈希链与时间线可复现,CTF 里可以「结果对就行」,但方法论必须一致,否则练出来的只是手熟而非能力。
本文按「容器格式 → 媒体载体 → 压缩包与流量 → 内存 → 磁盘 → 元数据 → 防御工程」的顺序组织,每节给出最小可复现的命令或代码,并附上对应的检测与防御视角。所有实验都在自建文件与本地靶场中完成,不涉及对他人系统的取证或数据获取。
想先建立全局观,可以先读 CTF 竞赛全景与学习路径 ;本专题的其他方向按 Web、Crypto、Reverse、Pwn 依次展开。
目录
- 文件格式与幻数识别
- 图片隐写:LSB 与 PNG 块结构
- JPEG、GIF 与 BMP 的隐写面
- 音频隐写:WAV、频谱与 MP3
- 压缩包与流量分析
- 内存取证:Volatility 3
- 磁盘与文件系统取证
- 元数据与时间线分析
- 检测与防御:从取证到 DLP
- 权衡取舍
- 常见坑清单
- 小结
1. 文件格式与幻数识别
幻数(magic number)是文件开头几个字节的固定值,也是判断「真实类型」的第一依据。file 读的正是幻数库,而 binwalk 会扫描整个文件里所有已知签名,因此能发现「PNG 里嵌 ZIP」这类拼接结构。
file mystery.bin # 看真实类型而非扩展名
xxd -l 64 mystery.bin # 手工核对前 64 字节
binwalk mystery.bin # 列出内嵌签名与偏移
binwalk -e mystery.bin # 按偏移分离(仅对本地自建文件)
foremost -i mystery.bin -o out/ # 按文件头尾特征 carving
strings -a -n 8 mystery.bin | head # 先捞一遍可读串
常见幻数要背下来:
| 格式 | 幻数(十六进制) | 偏移 |
|---|---|---|
| PNG | 89 50 4E 47 0D 0A 1A 0A | 0 |
| JPEG | FF D8 FF | 0 |
| GIF | 47 49 46 38 39 61 | 0 |
| ZIP | 50 4B 03 04 | 0 |
| RAR | 52 61 72 21 1A 07 00 | 0 |
25 50 44 46 2D | 0 | |
| ELF | 7F 45 4C 46 | 0 |
| PE | 4D 5A | 0 |
当扩展名与幻数不符时,一律以幻数为准;当幻数被故意改坏时,用 xxd 找已知块结构(如 PNG 的 IHDR/IEND)反推被改动的字节位置。修复时只需把正确幻数写回前几个字节,dd 或 Python 都可完成。
# 把被改坏的 PNG 幻数写回(本地自建文件)
data = bytearray(open("broken.bin", "rb").read())
data[0:8] = bytes.fromhex("89504E470D0A1A0A")
open("fixed.png", "wb").write(data)
要注意区分「解析」与「分离」:解析是按格式规范逐字段读,能得到结构与语义;分离(carving)是凭头尾特征切出字节流,快但可能切出碎片。怀疑多文件拼接时先分离再逐个解析,怀疑单文件被改坏时先解析定位异常字段。
还有一类是「结构合法但语义异常」:ZIP 的本地文件头与中央目录条目数量不一致、PNG 的 IHDR 宽度与实际数据长度不匹配、PDF 的 xref 偏移全错但对象可线性扫描。这些异常本身就是提示,通常指向「文件被手工拼接或截断」。
检测与防御:文件上传网关不应只信任扩展名或 Content-Type,而要做幻数校验与「魔改文件头」检测,防止用双扩展名或伪造 MIME 绕过白名单;同时应限制单文件体积与嵌套深度,避免解包放大(zip bomb)拖垮服务。
2. 图片隐写:LSB 与 PNG 块结构
LSB(最低有效位)隐写把信息写进像素值的最低位,视觉上几乎无差异。一张 24 位 RGB 图每个像素 3 字节,每字节藏 1 bit,1920×1080 的图理论上可藏约 777 KB。检测思路是先看「最低位是否近似随机」:自然图像的最低位有结构性,隐写后趋于均匀分布。
PNG 由 8 字节签名加若干 chunk 组成,每个 chunk 为「长度 4 字节 + 类型 4 字节 + 数据 + CRC32 4 字节」。关键块:IHDR 定义宽高与位深,IDAT 存 zlib 压缩后的像素,IEND 收尾;tEXt/zTXt/iTXt 是文本块,iTXt 支持 UTF-8 与压缩,是藏 flag 的高频位置;自定义块(如 tEXt 之外的私有类型)同样是线索。
import struct, zlib
data = open("challenge.png", "rb").read()
pos = 8
while pos < len(data):
ln = struct.unpack(">I", data[pos:pos+4])[0]
typ = data[pos+4:pos+8].decode("latin1")
crc = struct.unpack(">I", data[pos+8+ln:pos+12+ln])[0]
ok = (zlib.crc32(data[pos+4:pos+8+ln]) & 0xffffffff) == crc
print(typ, ln, "crc_ok=", ok)
pos += 12 + ln
CRC 校验是修复的关键:故意改坏 IDAT 一个字节后 PNG 无法解码,但只要 CRC 与实际数据不符,就能定位被篡改的块;反之若 CRC 与实际数据一致却解码失败,说明 CRC 被同步改过。工具上 zsteg -a 穷举 LSB 通道组合,pngcheck -v 逐块校验,stegsolve 的通道与位平面视图用于肉眼排查。
zsteg -a challenge.png # 穷举常见 LSB 组合
pngcheck -v challenge.png # 逐块 CRC 与结构校验
手工提取 LSB 时,先转成原始像素再按位组装。下面的最小复现只读自建文件,用于理解位序与通道顺序:
from PIL import Image
im = Image.open("challenge.png").convert("RGB")
px = list(im.getdata())
bits = [c & 1 for p in px for c in p] # 按 R,G,B 顺序取最低位
bits = bits[: len(bits) // 8 * 8]
out = bytes(int("".join(map(str, bits[i:i+8])), 2) for i in range(0, len(bits), 8))
print(out[:32])
判断「是否真的藏了东西」有个廉价方法:把图像按位平面拆开,正常图片的高位平面有清晰轮廓、低位平面呈噪声;若某一位平面出现可辨认的文字或图形,基本可以确定是隐写。再配合 zsteg 输出的 b1,rgb,lsb,xy 这类通道描述定位具体组合。
检测与防御:图片上传链路应做重编码(re-encode)剥离非必要块与元数据,丢弃 tEXt/iTXt 注释块,可一次性清除绝大多数文本类隐写;这同时也是元数据清理的常规操作。
3. JPEG、GIF 与 BMP 的隐写面
JPEG 是有损 DCT 压缩,直接改像素会破坏压缩结构,因此 JPEG 隐写多走两条路:改量化表,或在熵编码后的 DCT 系数里做文章(F5、OutGuess 等)。EXIF 是门槛更低的藏点,用 exiftool 全量导出即可看到 Comment、Artist、UserComment、XPComment 等字段。
exiftool -a -u -g1 photo.jpg # 含未知与私有标签
jpeginfo -c photo.jpg # 校验 JPEG 结构完整性
steghide info cover.jpg # 检测 steghide 隐写(口令可为空)
GIF 支持多帧与透明调色板,常见手法是在帧间延迟、调色板顺序或图形控制扩展块里藏数据;把 GIF 拆帧后逐帧比对差异,往往能发现异常像素块或帧数被刻意凑成 2 的幂。BMP 无压缩、结构直白,隐写通常直接改调色板或像素低位,用 stegsolve 的调色板视图最快。
convert anim.gif -coalesce frame_%03d.png # 拆帧
compare -metric AE a.png b.png null: # 逐帧差异计数
三种格式的藏点与检出手段可以对照记忆:
| 格式 | 典型藏点 | 检出手段 |
|---|---|---|
| JPEG | EXIF 文本字段、量化表、DCT 系数 | exiftool、重编码对比、系数直方图 |
| GIF | 帧延迟、调色板顺序、扩展块 | 拆帧比对、调色板导出 |
| BMP | 调色板、像素低位 | stegsolve 调色板视图、位平面 |
JPEG 的量化表值得单独看一眼:标准表有固定数值,若 exiftool 或 djpeg -verbose 输出的表项出现明显偏离标准表的取值,通常说明有工具在这里写过数据。频域隐写的容量通常远小于 LSB,所以「藏得下多少字节」也常被题目用来反向约束手法。
检测与防御:JPEG 重编码(质量 85 以上)会破坏大部分频域隐写;GIF 转静态或统一调色板会清除帧间隐写;企业侧更实用的是对图片做统一转码与 EXIF 白名单化,只保留必要的方向与色彩信息。
4. 音频隐写:WAV、频谱与 MP3
WAV 是最常见的音频隐写载体,因为它无损、样本值可直接按位操作。两条主线:一是 LSB,直接改 16 位采样值的低位;二是把数据编码成频谱图上的可见图案,典型是 SSTV,用频谱图肉眼读。
import wave, numpy as np
w = wave.open("secret.wav", "rb")
s = np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16)
bits = s & 1 # 取最低位
bits = bits[: len(bits) // 8 * 8].reshape(-1, 8)
head = bytes(int("".join(map(str, b)), 2) for b in bits[:8])
print(head) # 期望得到可读起始字节,如 b'flag'
MP3 是帧结构:每帧以 FF FB 或 FF F3 同步字开头,帧头含比特率索引、采样率索引与声道模式。隐写可以藏在帧头保留位,或在帧间插入自定义数据;DeepSound 会把加密数据附加到音频流并需要口令。分析顺序是先看波形与频谱,再看结构异常,最后才考虑口令类工具。
sox secret.wav -n spectrogram -o spec.png # 生成频谱图
mp3val -f secret.mp3 # 校验帧结构
频谱图用脚本生成更可控,可以调整窗长与重叠率让图案更清晰:
import numpy as np, matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from scipy.io import wavfile
from scipy import signal
fs, x = wavfile.read("secret.wav")
if x.ndim > 1:
x = x[:, 0]
f, t, S = signal.spectrogram(x, fs, nperseg=1024, noverlap=512)
plt.pcolormesh(t, f, 10 * np.log10(S + 1e-12))
plt.ylabel("freq (Hz)"); plt.xlabel("time (s)")
plt.savefig("spec.png", dpi=150)
MP3 帧头 4 个字节的字段顺序是:11 位同步字、2 位版本、2 位层、1 位保护位、4 位比特率索引、2 位采样率索引、1 位填充、1 位私有位、2 位声道模式。手工算帧长(如 128 kbps、44.1 kHz、无填充时为 417 字节)能快速定位被插入的异常帧。
检测与防御:音频出口检测应关注「非自然高频能量」与「静音段低幅随机性」;对上传音频做转码或重采样会破坏大多数 LSB 隐写。网络侧可结合 NetFlow 与流量可观测性 做异常外发体量与周期性检测,音频文件体积异常是弱信号。
5. 压缩包与流量分析
ZIP 是 Misc 出现频率最高的容器。三类问题:伪加密(本地文件头与中央目录的通用位标记不一致,09 00 表示加密),可用 zip -FF 或直接改标志位修复;CRC 爆破(小文件内容可枚举,用 CRC32 反查内容);明文攻击(已知压缩包内某个文件明文且压缩算法与参数一致时,可恢复密钥流,从而解开同包内其他文件)。
zipinfo -v secret.zip | grep -i encrypt # 看加密标记
unzip -l secret.zip # 列目录,看 CRC 与大小
bkcrack -C secret.zip -c known.txt -p plain.txt # 明文攻击(本地自建包)
zip2john secret.zip > h.txt # 生成字典攻击输入(授权环境)
john --wordlist=rockyou.txt h.txt
pcap 分析走「统计 → 追踪 → 导出」三步:先用 Wireshark 的 Protocol Hierarchy 与 Conversations 定位异常协议与流量峰值,再对可疑流做 Follow TCP/UDP Stream,最后用「导出对象」把 HTTP、SMB、TFTP 传输的文件还原。
tshark -r a.pcap -q -z io,phs # 协议分层统计
tshark -r a.pcap -q -z conv,tcp # TCP 会话表
tshark -r a.pcap --export-objects http,out/ # 导出 HTTP 对象
ZIP 的伪加密原理值得写清:本地文件头(LFH)与中央目录(CD)各有一个「通用位标记」字段,正常加密包两处都是 0x0001,伪加密只改了其中一处。手工修复就是把不一致的那个字节对齐,脚本化处理如下:
import struct
d = bytearray(open("fake_enc.zip", "rb").read())
# LFH 通用位标记在本地文件头的偏移 6 处,CD 条目在其结构内的偏移 8 处
def clear_lfh_flag(buf):
i = 0
while True:
i = buf.find(b"PK\x03\x04", i)
if i < 0:
return
buf[i+6:i+8] = b"\x00\x00"
i += 4
clear_lfh_flag(d)
open("fixed.zip", "wb").write(d)
流量题还有一类是「协议自造」:题目用自定义的 TCP/UDP 协议传数据,端口随意、载荷是二进制。这时不要急着看内容,先用 -z io,phs 找占比异常的那个协议,再用 -T fields -e data 把载荷按十六进制导出,最后按题目给的字段定义还原。
检测与防御:伪加密与 CRC 爆破只对弱口令与极小文件有效,企业侧应禁用 ZIP 传统加密、改用 AES-256(7z 的 -mhe=on 还会加密文件名);流量侧的重点是检测内网大流量外发与非常规端口上的 SMB/FTP 传输。
6. 内存取证:Volatility 3
内存镜像取证回答「当时系统上跑着什么」。Volatility 3 的调用方式是 vol -f image.raw <plugin>,插件按目标自动识别符号表(Windows 需下载符号,Linux 需匹配内核版本)。
vol -f mem.raw windows.info # 版本与时间基准
vol -f mem.raw windows.pslist # 进程列表
vol -f mem.raw windows.pstree # 进程树,看父子异常
vol -f mem.raw windows.cmdline # 命令行参数
vol -f mem.raw windows.netscan # 网络连接与监听
vol -f mem.raw windows.filescan # 文件对象扫描
vol -f mem.raw windows.malfind # 可疑内存段
vol -f mem.raw windows.dumpfiles --virtaddr 0x0 # 按对象地址导出
Linux 侧对应 linux.pslist、linux.bash、linux.sockstat。分析要点:malfind 命中 RWX 且无对应文件的页通常指向注入代码;pstree 里 explorer.exe 派生 cmd.exe 再派生 powershell.exe 是典型钓鱼链;cmdline 里的 base64 参数与 -enc 是常见混淆;netscan 里外部 IP 的非常规端口指向 C2。
典型的异常输出形态大致如下(自建靶场样本):
$ vol -f mem.raw windows.pstree
PID PPID ImageFileName Offset(V)
1234 1024 explorer.exe 0x8a01c2d0
2210 1234 cmd.exe 0x8a0f5b40
3320 2210 powershell.exe 0x8a11a080 <- -enc 参数
$ vol -f mem.raw windows.malfind
PID Process Start End Protection
3320 powershell.exe 0x1f0000 0x1f4000 PAGE_EXECUTE_READWRITE <- 无文件映射
把 malfind 命中的页 dump 出来后,先看前 2 字节是否为 4D 5A(PE 头)或 shellcode 特征,再决定是静态反汇编还是提取 C2 配置。内存取证与磁盘取证的区别在于:内存里有「运行时状态」,包括已解密的内存字符串与网络会话,这是磁盘上没有的。
检测与防御:内存取证的价值在于绕过磁盘上被清理的痕迹。生产环境的对应能力是启用 ETW/Sysmon 记录进程创建与镜像加载、开启 PowerShell 脚本块日志,并把事件汇入 SIEM 与安全运营 做关联告警。
7. 磁盘与文件系统取证
磁盘取证从分区表开始:MBR 分区表在偏移 0x1BE 起的 4 个 16 字节表项,GPT 有主备两份头(LBA1 与磁盘末尾),备份 GPT 是修复被破坏主头的关键。已删除文件恢复的原理因文件系统而异:FAT 与 ext4 只删除目录项与位图标记,数据块仍在;NTFS 的 MFT 记录会保留常驻属性的前若干字节,小文件常可直接恢复。
mmls disk.img # 列出分区与偏移
fls -r -o 2048 disk.img # 递归列文件(前缀 * 为已删除)
icat -o 2048 disk.img 128 > out.bin # 按 inode 提取内容
tsk_recover -o 2048 disk.img out/ # 批量恢复已删除文件
debugfs -R "lsdel" /dev/sdb1 # ext4 删除记录(只读挂载下)
ext4 与 NTFS 的差异要点:
| 维度 | ext4 | NTFS |
|---|---|---|
| 元数据 | inode 表 + extent 树 | MFT 记录 + 常驻属性 |
| 删除语义 | 位图清标记,数据块留存 | MFT 记录标记为可用,内容可能保留 |
| 日志 | journal(元数据) | $LogFile(重做/撤销)、$UsnJrnl(变更) |
| 时间戳 | ctime/mtime/atime | SI 与 FN 两套 MACB |
| 恢复窗口 | 较小(inode 复用快) | 较大(MFT 与日志留存) |
做只读分析必须用 -o ro 挂载或直接对镜像操作,避免写入破坏证据。镜像采集与分区结构的更多细节见 Linux 文件系统与磁盘
。
检测与防御:取证链完整性要求对镜像做 SHA-256 并在每一步记录哈希,任何一次写入都视为污染;企业侧对应的是终端 EDR 的原始事件留存与磁盘加密(BitLocker/LUKS),后者能让离线取证在无密钥时直接失效。
8. 元数据与时间线分析
元数据是最容易被忽略的证据来源。EXIF 含拍摄时间、设备型号、GPS 坐标;Office 文档含作者、修订历史与最后保存者;PDF 含生产者与创建工具。时间线分析的核心是 MACB:Modified、Accessed、Changed(MFT 元数据变更)、Born(创建)。NTFS 的 $STANDARD_INFORMATION 与 $FILE_NAME 各存一份时间,攻击者用工具改前者时后者往往残留原值,这就是时间戳伪造的检测点。
exiftool -time:all -a -G1 file.jpg
fls -m -o 2048 disk.img > body.txt # mactime 输入
mactime -b body.txt -d 2026-10-01..2026-10-07 > timeline.csv
strings -a -n 6 file.bin | head # 快速捞可读串
时间戳的四个维度与常见伪造痕迹:
| 时间戳 | 含义 | 伪造时的残留 |
|---|---|---|
| Modified | 内容最后修改 | 与 $LogFile 记录不一致 |
| Accessed | 最后访问 | 常被系统策略关闭,参考价值低 |
| Changed | MFT 元数据变更 | 改时间戳时它一定会变,是破绽 |
| Born | 创建时间 | 早于父目录创建时间即异常 |
超级时间戳把文件系统、注册表、日志、浏览器历史统一到一条按时间排序的记录流,是真实取证的核心产物。CTF 里的简化版就是「把所有可疑时间点排成一列,找出与题目描述矛盾的那一个」。
检测与防御:外发文件必须剥离元数据,否则等于泄露内网结构、账号名与设备指纹;DLP 规则应覆盖「含 GPS 或作者字段的文档外发」这类场景,同时注意元数据清理本身也可能被用作反取证手段,需保留原始副本。
9. 检测与防御:从取证到 DLP
把 Misc 的技术面反过来看,就是一组明确的防御要求:
| 载体 | 常见隐写手法 | 防御措施 |
|---|---|---|
| PNG/BMP | LSB、tEXt/iTXt 文本块 | 上传后重编码、剥离注释块 |
| JPEG | EXIF 字段、量化表 | EXIF 白名单化、统一转码 |
| GIF | 帧延迟、调色板 | 转静态或统一调色板 |
| WAV/MP3 | LSB、频谱、附加数据 | 转码或重采样、体积与频谱异常检测 |
| ZIP | 伪加密、弱口令 | 禁用传统加密、改用 AES-256 |
| 流量 | 隧道、分片外发 | 出口流量基线与 NetFlow 检测 |
| 内存/磁盘 | 注入、反取证 | ETW/Sysmon 留存、磁盘加密 |
三条工程启示:一是「输入一律重编码」是最省成本的通用防御,能清除绝大多数载体层隐写;二是「元数据默认剥离」应做成上传链路的默认行为而非可选开关;三是取证能力必须落到日志留存上,没有留存的系统在事件发生后无法复盘,日志的分层与采样设计决定了能查到什么粒度。
把上面的措施落成可执行的流水线,大致是这样一条最小链路:
# 上传落盘后的统一处理(示意,仅含本地工具)
identify -format "%m %wx%h\n" raw.png # 校验真实格式与尺寸
convert raw.png -strip -define png:exclude-chunks=tEXt,iTXt,zTXt \
-quality 88 clean.jpg # 去元数据 + 重编码
exiftool -all= clean.jpg # 二次确认清空
sha256sum raw.png clean.jpg > chain.txt # 记录哈希,保留原始件
这段脚本体现了取证与防御的同一套原则:原始件只读保留、处理产物单独输出、每一步留哈希。若把 sha256sum 换成 openssl dgst -sha256 并加上时间戳与操作人,就是一份最小可用的证据链记录。
权衡取舍
| 场景 | 优先手段 | 理由 | 局限 |
|---|---|---|---|
| 未知文件、怀疑拼接 | binwalk + foremost | 按签名扫描,覆盖多层嵌套 | 无签名的手工结构会漏 |
| 图片疑似 LSB | zsteg + pngcheck | 穷举通道与位平面,速度快 | 加噪或加密后无效 |
| 图片疑似频域隐写 | 重编码后对比 | 破坏隐写同时保留视觉 | 有损,不适合取证原始件 |
| 音频可疑 | 频谱图肉眼 | 对 SSTV 类最直接 | 对纯 LSB 无效 |
| 内存镜像 | Volatility 3 | 插件覆盖进程、网络、文件 | 需匹配符号与内核版本 |
| 磁盘恢复 | 只读挂载 + TSK | 不破坏证据链 | 删除后写入会快速覆盖 |
| 生产防御 | 重编码 + 元数据剥离 | 一次清除多数载体隐写 | 对流量隧道无效 |
选型的判断标准其实只有一条:先确定「信息藏在哪一层」,再选该层最省力的工具。跳过层级判断直接上工具,是 Misc 里最常见的浪费。
常见坑清单
- 只看扩展名就下结论 ——
file与xxd才是第一手依据,扩展名可以随意改。 - 忽略 CRC —— PNG 块 CRC 不符说明被篡改,先修 CRC 再解码,否则工具报错会误导方向。
- 在生产文件上直接跑 binwalk -e —— 会写出大量文件,务必先复制到工作目录再操作。
- LSB 提取顺序错 —— 通道顺序(R/G/B/A)与位序(MSB/LSB)任一处错都得到乱码,先用已知明文验证。
- 把「随机最低位」当成隐写 —— 高压缩率图片的最低位本身就近似随机,需与对照组比较再判断。
- 内存镜像未做哈希 —— 取证链断裂,结论无法复现,也无法作为正式报告依据。
- 用可写方式挂载证据盘 —— 一次写入即污染,必须
-o ro或直接对镜像操作。 - 时间戳只看一个来源 —— NTFS 两套时间、日志与注册表时间要交叉验证才可靠。
- 把字典爆破当通用解 —— 只对弱口令有效,AES-256 与传统加密的爆破成本差数个量级。
- 在非授权环境复现 —— 隐写与取证技术只能用于自建靶场与书面授权范围。
小结
Misc 的技术栈看起来零散,实际有一条清晰主线:先判断容器格式与层级,再选该层的解析工具,最后用「重编码或重采样」这类通用手法做交叉验证。把幻数、块结构、CRC、帧结构、分区表、时间戳这几组基础概念吃透,工具只是实现细节。
从工程角度看,这一篇最大的价值不是解题技巧,而是反向的防御清单:上传重编码、元数据剥离、出口流量基线、磁盘加密、日志留存,每一条都能在真实环境里落地,且成本可控。
下一步建议按本专题的顺序补 Web 与 Crypto 方向,再回头看工具链与协作那一篇,把零散技巧串成可复用的流程。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。