一,windows
1,电脑端下载东西
软件下载阶段
先来介绍下载的内容主要形式,两种安装包:
单文件便携程序:xxx.exe 可直接运行,不用安装;安装包程序:xxx.exe/xxx.msi
具体流程
-
双击
setup.exe,程序先解压内部资源(类似安卓解压 APK); -
释放核心文件:
-
主程序
xxx.exe(PE 格式,Windows 专属可执行文件) -
依赖库
xxx.dll(动态链接库,对应安卓.so) -
配置文件、图标、资源、驱动
.sys
-
-
写入注册表(安卓无注册表,这是 Windows 特有),注册桌面快捷方式、开始菜单
这里出现一个不常见的内容叫做dll
依赖 DLL"是什么意思?
假设你下载了一个:
xxx.exe
但是运行的时候弹出来:
无法启动此程序,因为计算机中丢失 xxx.dll
这句话实际上是在说:
"xxx.exe 运行的时候,需要 xxx.dll,但是 Windows 没找到它。"
所有的代码不是都在源码中的,就像是课上c语言学的include,是引入了一部分已经写好的代码,但是和include这种静态链接还是有区别的
动态链接
另一种:
A.exe
│
│ 需要某个函数
↓
xxx.dll
│
↓
执行 DLL 中的代码
DLL 不塞进 EXE。
运行的时候再加载。
Windows Loader 找:
A.dll
你的程序
xxx.exe
│
┌────────┼────────┐
↓ ↓ ↓
A.dll B.dll C.dll
│ │
↓ ↓
D.dll E.dll
编译的时候,编译器/链接器就已经知道这个函数属于哪个库;程序运行时,Windows Loader 按照程序记录的依赖关系去加载 DLL,然后把函数对应的地址找出来。
2,电脑端运行应用
- 双击快捷方式,系统加载 PE 可执行文件
xxx.exe; - 操作系统自动检索并加载程序依赖的
.dll文件:- 程序目录内的 dll、系统目录自带 dll;
- 缺失 dll 会直接报错打不开软件;
- exe 上层代码运行,需要高性能底层功能(音视频、游戏)就调用 dll;
- 读取本地图片、配置资源,渲染窗口界面,软件启动完成。
二,andorid
一个android的apk解压缩后你看到的内容基本上是:
- 文件后缀
.apk,底层是 zip 压缩格式,电脑把后缀改成.zip就能解压查看内部全部文件。
app.apk
│
├── AndroidManifest.xml
├── classes.dex
├── classes2.dex
├── resources.arsc
├── res/
├── assets/
└── lib/
├── arm64-v8a/
│ └── xxx.so
└── armeabi-v7a/
└── xxx.so
xml是图片、布局、配置清单 ,AndroidManifest.xml定义 APP 图标、权限、启动页面
其他的东西是啥后面会细致的讲解
1,手机端下载东西
.apk本质就是改了后缀的 .zip 压缩包,把所有代码、资源、库打包在一起;.aab是谷歌商店分发包,不会直接给用户,商店后台自动拆分生成.apk再下发手机;.so:Linux ELF 二进制原生库(C/C++ 代码),对应 Windows.dll;.dex:安卓虚拟机可执行代码(Java/Kotlin 编译产物,存在 apk 内部)
dex是啥
就像是java运行的class文件编译成机器码,让cpu读,c读取c文件编译成机器码让cpu读,dex是art运行读取的文件,读取成机器能动的语言,art是android的一个虚拟环境
那 Android 到底怎么执行 DEX?
这里就和你刚才问 DLL 的问题联系起来了。
现代 Android 主要使用:
ART(Android Runtime)
以前 Android 使用的是:
Dalvik
所以 DEX 这个名字来自 Dalvik。
现在大概是:
APK
│
↓
classes.dex
│
↓
ART
│
┌─────┴─────┐
↓ ↓
解释/JIT AOT
│ │
└─────┬─────┘
↓
机器代码
↓
ARM64 CPU
ART 会把 DEX 中的代码变成 CPU 可以执行的机器代码。
对比来说就是

所以安装的流程是
校验与权限解析
读取 AndroidManifest.xml:
-
获取 APP 名称、图标、申请的权限(存储、相机、网络);
-
标记启动 Activity(打开 APP 第一个页面);
-
校验安装包签名,盗版 / 修改过的 apk 会提示安装失败。
优化编译 dex → odex(系统预编译)
安卓 ART 虚拟机不能直接裸跑 dex,安装时会把 classes.dex 编译成机器码 .odex 文件,存在系统分区,加快后续启动速度。
文件部署到系统私有目录
安装完成后,apk 原始压缩包不会留在下载文件夹(你手动保留的除外),系统把解压后的资源、.odex、.so 全部移动到 APP 专属私有目录
2,手机端运行应用
- 系统唤醒 ART 虚拟机
点击图标,系统读取 AndroidManifest.xml 找到启动页面,启动 ART 虚拟机(安卓专属运行环境)。
- 加载预编译
.odex(Java/Kotlin 代码)
虚拟机读取安装时生成的 .odex 文件,直接运行业务逻辑(界面、按钮、网络请求等上层代码)。
原始
.dex只是 apk 里的打包源码,真正运行用优化后的 odex。
- 加载
.so原生库(C/C++ 底层功能)
如果 APP 用到音视频、游戏、加密、爬虫、高性能计算,会调用 libxxx.so 文件:
-
.so是 Linux 标准 ELF 可执行文件,安卓底层基于 Linux 内核,能直接解析; -
对应 Windows
.dll、Linux 服务器原生程序; -
游戏、短视频 APP 一定会携带多个架构的
.so(32 位 / 64 位),手机自动匹配对应架构库。
- 渲染资源,弹出界面
虚拟机读取 apk 内的图片、布局资源,渲染出 APP 首页(清单里定义的启动 Activity),APP 正式打开可操作。
三,这两者中的安全问题
经过学习我们了解了过程是
下载
↓
安装
↓
PE加载
↓
DLL加载
↓
程序运行
↓
访问文件/网络/设备
好了理解了这些下载安装的流程,我们在看一下用户的流程
用户
↓
搜索软件
↓
下载 xxx.exe
↓
双击
↓
恶意程序运行
windows主要安全问题
1 ,假软件 / 木马
比如:
正版:
Chrome.exe
恶意:
Chrome.exe
文件名完全一样,但内容完全不同。
2. 安装包被篡改
比如你从某个网站下载:
setup.exe
原本:
setup.exe
├── xxx.exe
├── xxx.dll
└── resource
攻击者如果能够修改安装包:
setup.exe
├── xxx.exe
├── xxx.dll
├── resource
└── malware.exe ← 恶意代码
那么你安装的时候:
setup.exe
↓
释放文件
↓
执行恶意代码
所以这里就出现了:
数字签名
Windows 软件经常可以查看:
属性
→ 数字签名
数字签名的核心目的之一就是:
证明这个文件确实来自某个发布者,并且签名之后没有被修改。
3,DLL:这里是非常重要的安全问题
假设:
C:\Program\xxx.exe
需要:
abc.dll
正常:
xxx.exe
↓
Windows Loader
↓
abc.dll
但是如果攻击者能够把一个恶意的 abc.dll 放到程序搜索路径里:
C:\Program\abc.dll ← 正版
变成:
C:\Program\abc.dll ← 恶意 DLL
那么:
xxx.exe
↓
加载 abc.dll
↓
恶意代码执行
这就是非常经典的一类问题:
DLL Hijacking(DLL 劫持)
- DLL 为什么能变成攻击面?
因为 DLL 不只是"一个文件"。
它里面是:
代码
↓
函数
↓
CPU执行
所以:
正常 DLL:
xxx.exe
↓
good.dll
↓
正常代码
被替换:
xxx.exe
↓
evil.dll
↓
攻击者代码
这就是你学习 DLL 后特别应该建立的一个安全意识:
"依赖库 = 外部代码",所以加载依赖库本身就是一个安全边界。
Android安全问题
1,APK下载:和 Windows 一样,首先是"APK是不是正版?"
例如:
正版 App
↓
official.apk
攻击者:
恶意 App
↓
official.apk
用户根本不知道。
所以 Android 有一个非常重要的机制:
APK 签名
可以简单理解成:
开发者
↓
私钥签名
↓
APK
↓
手机验证签名
如果有人修改 APK:
正版 APK
↓
修改 classes.dex
↓
恶意 APK
原来的签名就不再匹配。
所以你写的:
"盗版 / 修改过的 apk 会提示安装失败"
这个说法需要修改一下。
更准确地说:
Android 会验证 APK 签名,但"修改过的 APK 一定安装失败"并不绝对。攻击者可以重新签名,用户是否能安装取决于安装来源、Android版本、签名方案、是否存在旧版本以及应用自身的签名校验等情况。
这个区别在 Android 安全里很重要。
2,Android 的沙箱
Android 每个 App 通常有自己的 Linux UID:
App A
UID 10001
App B
UID 10002
App C
UID 10003
于是:
App A
↓
自己的数据目录
App B
↓
自己的数据目录
正常情况下:
App A ❌ → App B 私有数据
这就是:
Android Application Sandbox(应用沙箱)
所以 Android 安全模型可以粗略理解成:
Android
│
┌────────┼────────┐
↓ ↓ ↓
App A App B App C
│ │ │
UID A UID B UID C
│ │ │
沙箱 沙箱 沙箱
3,so:这是 Android 另一个非常重要的攻击面
例如:
lib/arm64-v8a/libxxx.so
里面可能是:
C/C++
↓
编译
↓
ARM64机器码
这里就出现传统 Native 安全问题:
缓冲区溢出
Use-After-Free
整数溢出
格式化字符串
内存破坏
所以 Android 的 Native 层安全非常重要。
例如:
Java/Kotlin
↓
JNI
↓
libxxx.so
↓
C/C++
如果 JNI 接口处理不安全:
Java传入恶意数据
↓
JNI
↓
C/C++
↓
Buffer Overflow
就可能产生严重漏洞。
4. Android 运行阶段还有一个很重要的东西:IPC
这个你现在的笔记里还没有。
Android App 并不是完全孤立的。
它们需要和:
系统服务
其他App
Framework
通信。
其中非常重要的机制就是:
Binder IPC
例如:
App
↓
Binder
↓
Android System Service
所以 Android 安全研究里会大量看到:
Activity
Service
Broadcast Receiver
Content Provider
Binder
IPC
这些都是攻击面。