2022-回放-05:二进制与文本文件 · 伪装文件检测作业 · 模块与包 · 第三方库与虚拟环境¶
内容梗概¶
本次直播回放围绕三大块内容展开。第一块讲"文件与目录"章节的核心概念:二进制文件与文本文件的本质区别、字符编码、二进制文件的结构(文件头/文件特征),并结合网安专业背景讲解 PE/ELF 可执行文件格式与 CTF 题目中的文件格式篡改思路,顺势布置了"遍历目录检测伪装文件"的作业。第二块串讲"模块与包":模块名即文件名、import 的执行机制、if __name__ == '__main__' 的原理、模块搜索路径 sys.path、包与 __init__.py。第三块以一个学生装包失败的真实案例引入"第三方库与虚拟环境":pip 与 python 环境错位的排查、虚拟环境的意义、pipenv + Pipfile 的工作流、whl 文件命名规则、查找命令路径的技巧,最后对比了 Python 与 Anaconda。
知识点详解¶
一、二进制文件与文本文件(约 00:00 - 00:27)¶
- Python 中的两种二进制数据类型(约 01:10):
bytes不可变(初始化后内容不能改,但可以追加拼接);bytearray像列表一样可以修改中间的字节。base64 作业中已接触过。 - 文本文件 vs 二进制文件(约 03:20 - 14:45):
- 对计算机而言没有区别,所有文件本质上都是二进制序列;区别是**程序员/工具视角**的。
- 能被文本类工具(文本编辑器、
cat、echo等命令行工具)直接读写的文件就是文本文件;文本文件的存取流程只有最简单的**编码与解码**一步(open的encoding参数如 UTF-8)。 - 二进制文件不能通过统一的编解码直接转成字符,它们**都有固定的文件格式**:文件头 + 按固定结构组织的元信息 + 数据(如 BMP 的长宽高位深度;Word 文档同理),读取软件必须按格式解析才能正确显示。
- 历史原因:早期计算机围绕字符界面的 shell 发展,围绕文本文件的工具极多。
- 从 API 层面看:打开文件的 mode 中,
r/w/a默认是文本模式,加b(rb/wb/ab)才是二进制模式。 - 字符集与字符编码(每个字符对应哪个二进制序列的规定)在"字符集与编码"录播视频中讲过,本课不重复。
- 安全专业视角(约 16:00):逆向、恶意代码分析、漏洞挖掘面对的大多是二进制文件;所有可执行文件都是二进制的——Windows 的 .exe/.dll 统称 PE(Portable Executable,可移植可执行文件),Linux 下对应 ELF。双击 exe 时操作系统按文件结构(DOS 头、signature 签名即
MZ等)解析后执行。 - 文件破损的不同后果(约 20:00):二进制文件格式精密,头被篡改可能整个跑不起来;文本文件损坏通常只丢损坏部分或出现乱码。
- CTF 例题思路(约 21:10):给一张只显示上半截的图片,可能是出题人把 BMP 头中的高度值(如 1080 改成 540)改小了,黑色下半部分藏着 flag;解法是写程序或用二进制编辑器把高度改回去。
- docx 本质是 zip(约 25:00):新建 Word 文档贴图保存后,把
.docx改后缀为.zip解压,可在word/media里找到image1.png——二进制格式远比文本复杂,不可能用编解码直接读出。 - 文本文件泄露隐私 vs 二进制文件带毒(约 26:55):文本文件本身不会让你中毒(但可能泄露隐私),安全研究的对象绝大多数是二进制文件。
二、作业:伪装文件检测(约 27:30 - 43:00)¶
- 背景:钓鱼邮件案例——伪装成"国台办通知"的邮件附件,图标改成 Word 文稿样式的
.exe。普通用户因资源管理器默认不显示扩展名而上当(《计算机安全与维护》第一课就要求勾选"文件扩展名")。 - 检测原理:每种文件类型的**文件头特征**不同——exe/PE 开头两字节是十六进制
5A 4D(即字符MZ),JPG 开头是FF D8,PNG 开头是89 50 4E 47(\x89PNG),PDF、BMP、DOCX、TXT 等各有特征。读取文件头与后缀名比对,不一致即为伪装文件。 - 杀毒软件同理(约 36:30):病毒库存的就是病毒二进制文件的特征(文件头特征相同,但代码段各有特征),全盘扫描就是逐个打开二进制文件匹配特征。
- 作业要求(约 39:30):给定一个含多个文件夹的目录,里面的文件(如"考研讲义.pptx"等诱人名字)中混有 exe 伪装的文件;要求写程序**遍历目录**,读取每个文件的文件头特征与后缀比对,一致视为正常、不一致视为异常,分别放入正常/异常两个文件夹。需结合录播视频"目录遍历"部分完成(该视频讲得很细)。有兴趣可以遍历整个 C 盘。
三、模块与包(约 44:00 - 01:23:30)¶
- 模块概念(约 45:50):任何
.py文件都是模块,模块名 = 去掉后缀的文件名(calc.py→ 模块calc;作业.py→ 模块"作业")。第三方库(PIL、OpenCV)也只是别人起的名字。 - 符号(symbol)与
dir()(约 47:25):dir(模块名)列出模块中所有符号;符号包括顶格定义的全局变量、函数、类(关联编译原理的词法/语法分析概念)。通过模块名.符号名访问,如calc.sum()。 - import 会执行整个模块(约 50:40):导入模块时 Python 解释器把模块所有语句**逐行执行一遍**(否则函数定义就不存在)。演示:
main.py里只写import calc,运行 main 也会打印 calc 里的print语句。 if __name__ == '__main__'(约 53:50 - 01:01:00):- 用途:模块内写测试代码,直接运行该脚本时执行、被别人 import 时不执行。否则协作开发时忘删测试语句会让使用者看到莫名其妙的输出。
- 原理:双下划线变量是 Python 内置变量(自己不要起这种名字)。
__name__随运行方式变化:直接运行python calc.py时值为'__main__';被 import 时值为模块名字符串(如'calc'),条件不成立故测试代码不执行。 - 模块搜索路径
sys.path(约 01:01:30 - 01:13:00):import xxx时先查**内置模块**(如sys,内置在解释器中,没有对应 .py 文件——课堂上一度想从安装目录找 sys.py 翻车),再按sys.path列表顺序搜索。print(sys.path)可见优先级:① 当前脚本所在目录;② 某些 zip 路径;③ 安装目录的 DLLs、lib;④ Python 根目录;⑤site-packages(网上下载的第三方包就装在这里,如 bs4)。理解搜索路径是为后面多环境下装包问题做铺垫。 - 包(package)(约 01:13:55):模块的升级版——多个 .py 文件(甚至多级目录)组成的库,如 bs4 就是一个文件夹。每个包(含子包)必须有
__init__.py作为入口:import 包时优先执行它(如from bs4 import BeautifulSoup实际导入的是 bs4 的__init__.py中定义的类)。包可层层套娃,缺__init__.py会报警告。 - 子包相对导入(约 01:19:00):包内模块互相导入用相对路径写法:
from . import xxx(当前目录)、from ..fx import echo(上一级),注意用点而非斜杠分隔。 - 不推荐
from pkg import *(约 01:21:00):通配符会把包里所有模块全部加载执行一遍,效率低,不符合"操作精确"的最佳编程实践。
四、第三方库与虚拟环境(约 01:24:00 - 02:18:00)¶
- 真实案例引入(约 01:24:40):某同学装
wifipumpkin(无线钓鱼实验库,原理:设备会自动连同 SSID 的热点,伪造同名无密码热点即可钓鱼)报错——asn1crypto 需要 ≥1.5.1 而机器上是 1.4.0;但pip3 list明明显示装的是 1.5.1,百思不得其解。 - 排查关键命令(约 01:31:25):
pip -V(大写 V,等价于--version;pip --help可查所有命令与选项),会同时显示 pip 对应的安装路径。对比发现:安装用的是/usr/local/lib/python3.9/dist-packages,而 pip3 list 看的是/usr/lib/python3/dist-packages——python 和 pip 分属两个不同的环境。该同学机器上甚至有 4 个 Python 版本。 - 原因与重现(约 1:35:45 - 1:45:50):与 Python 相关的环境变量有两个——
python.exe所在目录和Scripts(pip.exe 所在)目录;两者指向不同环境时,命令行里的 python 与 pip 就错位了。老师现场改环境变量重现该 bug,再改回来修复。注意该同学是因为用sudo python3 setup.py install(而非 pip)安装才触发版本冲突。 - 启发(约 01:45:54):① 环境变量配置错误会导致 pip 装的包与 python 用的环境对不上(装了 bs4 却 import 不进来就是典型);② Python 环境的构成——正规安装:根目录有
python.exe、pythonw.exe(无黑框静默运行脚本)、DLLs、Lib(内含site-packages)、Scripts(内含 pip);虚拟环境则更精简,Scripts里 python/pythonw/pip 全在一起,还有配置文件记录它是从哪个环境克隆的。 - 虚拟环境的意义(约 01:50:43):不同项目需要不同版本的 Python 和第三方库,共用一个环境会互相覆盖冲突;用
virtualenv为每个项目建独立环境(如换脸项目只装 OpenCV,另一个项目只装 pandas/openpyxl),互不干扰,做完可直接删除(不影响主环境,还能省几百兆空间)。现代语言(Node.js、Go 等)都有类似机制。 - 包管理系统回顾(约 01:54:00):macOS、Linux 都有包管理机制;pip 安装流程(查索引服务器拿版本与下载地址 → 下载 → 编译 → 装依赖 → 安装)在录播视频里用
pip -vvv install xxx(v 越多日志越详细,注意与pip -V区分)演示过。 - 镜像源:改成国内源只为加速,照录播课件配置即可(阿里源)。
- whl 离线安装与命名规则(约 01:57:20):whl 文件名短横线分隔的部分不能随便改,必须按规范:版本号 -
cp310(CPython 3.10,即默认的 C 语言版解释器)-win_amd64(64 位 Windows)。可去热心群众维护的 Windows 平台编译 whl 站点下载。 - pipenv 工作流演示(约 01:59:50 - 02:12:50):
- 环境管理工具有 virtualenv、venv、pyenv、pipenv 等(内置或第三方),老师偏好 pipenv。
- 一个目录 = 一个项目;进入目录执行
pipenv install(没有 pipenv 先pip install pipenv——pipenv 本身也是个 Python 包),自动生成Pipfile和Pipfile.lock(lock 不用管)。 - 改源:打开
Pipfile把[[source]]的 url 从官方源改成阿里镜像。 pipenv shell进入虚拟环境;装包要用pipenv install pillow(而不是pip install),因为前者会把包名与版本写进Pipfile,后者不会。- 一键重建:删掉
.virtualenvs下的环境目录后,只要Pipfile还在,再执行pipenv install就会自动按 Pipfile 把 pillow、requests 等全部装回——分享项目时只需发代码 + Pipfile(lock 可不发)。 Pipfile里的python_version记录环境所用 Python 版本(如 3.9);创建时也可指定其他版本(如 2.7),pipenv 会自动去本机找对应版本。- 环境变量 PATH 里上面的 Python 优先生效;VS Code 会自动扫描
.virtualenvs等常见目录识别出所有环境列在右下角。 - 查找命令路径的技巧(约 02:00:20):Linux 用
which python;Windows cmd 用where python.exe;PowerShell 没有 where,用gcm(Get-Command缩写)。当命令找不到或版本不对时,先用它确认当前命令行解析到的是哪个目录。 - Python 与 Anaconda(约 02:15:00):完全不同的两个概念。Anaconda 安装包约 500 多 MB(Python 官方安装包仅约 25-30 MB,差约 20 倍),因为自带 numpy 等大量科学计算包,一体化省心但"全家桶"式;非计算机专业可以用,计算机专业建议自己管理环境(个人偏好,不强制)。
示例与演示¶
- 伪装文件现场演示:把
python.exe改成"比特币钱包.docx",说明图标可改、扩展名默认隐藏导致钓鱼得逞;引出用文件头特征(MZ/5A4D)识别真实文件类型的思路。 - 作业:遍历给定目录,按文件头特征(JPG/PNG/BMP/PDF/DOCX/PPT/TXT/EXE 的特征表已给出)与后缀比对,把 exe 伪装的文件筛进"异常"文件夹——相当于写一个小型杀毒扫描器。
- import 执行机制演示:
calc.py(含 print 和函数)+main.py(仅import calc),运行 main 也会执行 calc 的 print;加if __name__ == '__main__':后 import 不再触发测试代码。 - sys.path 演示:
print(sys.path)看搜索顺序;Ctrl+点击 bs4 跳转到 site-packages 下的__init__.py,直观理解包结构。 - pip/python 环境错位重现:改环境变量把 Scripts 指向另一环境 →
where python与pip -V路径不一致 → 再改一致修复。 - pipenv 完整流程:
pipenv install→ 改 Pipfile 源 →pipenv shell→pipenv install pillow/pipenv install requests→ 删除虚拟环境目录 → 再次pipenv install一键恢复。
重点与难点¶
- 文本文件只有"编码/解码"一层,二进制文件有自定义格式与文件头——这是本课全部内容与作业的理论基础。
- 文件头特征(magic number):PE/exe 是
MZ(5A4D),JPG 是FF D8,PNG 是89 PNG;文件后缀可以被随便改,文件头不会说谎。 - import 模块 = 逐行执行模块全部语句;
__name__在直接运行时是'__main__'、被导入时是模块名——if __name__ == '__main__':的原理必须理解而非死记。 - 包必须有
__init__.py作为入口;包内相对导入用点号(.、..)而非路径斜杠。 - 不用
from x import *:全量加载低效且不精确。 - pip 与 python 必须是同一环境:排查用
pip -V(看路径)、where/gcm/which(看命令解析路径)、检查两个 Python 相关环境变量是否一致。"装上了却 import 不到"九成是环境错位。 - pipenv 装包要用
pipenv install(写入 Pipfile),用pip install虽然能装上但不会记录,破坏一键重建能力。 - whl 文件名不能乱改,命名规范包含版本、解释器(cp310)、平台(win_amd64)信息。
- 模块搜索顺序:内置模块 → sys.path(当前目录优先,site-packages 靠后);命名自己的文件时不要与标准库/第三方库重名(呼应后面回放-06 中 flask.py、abc.py 翻车)。
关联内容¶
- 对应录播章节:"数据类型进阶与输入输出"之后的"文件与目录"(字符编码、目录遍历视频讲得很细)、"模块与包"、"第三方库与虚拟环境"各节;whl 命名规则在"课程概述/基本概念"中讲过。
- 前置:base64 作业(bytes 操作)、《计算机安全与维护》(环境变量、文件扩展名、字节序、数据恢复章节中 txt 在硬盘上的 ASCII 存储演示)。
- 后续:Web 开发、爬虫、数据可视化三大实战大量依赖第三方库与虚拟环境,本节是必修前置;bs4(BeautifulSoup)在爬虫章节使用;目录遍历能力与本次伪装文件检测作业直接配合。
- 安全专业关联:PE/ELF 文件结构、病毒特征库、钓鱼与无线钓鱼(SSID 伪装)案例,呼应后续逆向工程、软件安全课程与 CTF。