第0章 恶意代码分析技术入门 1
0.1 恶意代码分析目标 1
0.2 恶意代码分析技术 2
0.2.1 静态分析基础技术 2
0.2.2 动态分析基础技术 2
0.2.3 静态分析高级技术 2
0.2.4 动态分析高级技术 2
0.3 恶意代码类型 3
0.4 恶意代码分析通用规则 4
第1篇 静态分析 6
第1章 静态分析基础技术 6
1.1 反病毒引擎扫描:实用的第一步 6
1.2 哈希值:恶意代码的指纹 7
1.3 查找字符串 7
1.4 加壳与混淆恶意代码 9
1.4.1 文件加壳 10
1.4.2 使用PEiD检测加壳 10
1.5 PE文件格式 11
1.6 链接库与函数 12
1.6.1 静态链接、运行时链接与动态链接 12
1.6.2 使用Dependency Walker工具探索动态链接函数 13
1.6.3 导入函数 14
1.6.4 导出函数 15
1.7 静态分析技术实践 15
1.7.1 PotentialKeylogger.exe:一个未加壳的可执行文件 15
1.7.2 PackedProgram.exe:穷途末路 18
1.8 PE文件头与分节 18
1.8.1 使用PEview来分析PE文件 19
1.8.2 使用Resource Hacker工具来查看资源节 22
1.8.3 使用其他的PE文件工具 23
1.8.4 PE文件头概述 23
1.9 小结 24
1.10 实验 24
第2章 在虚拟机中分析恶意代码 27
2.1 虚拟机的结构 27
2.2 创建恶意代码分析机 28
2.2.1 配置VMware 29
2.2.2 断开网络 30
2.2.3 创建主机模式网络 30
2.2.4 使用多个虚拟机 30
2.3 使用恶意代码分析机 31
2.3.1 让恶意代码连接互联网 31
2.3.2 连接和断开外围设备 32
2.3.3 拍摄快照 32
2.3.4 从虚拟机传输文件 33
2.4 使用VMware进行恶意代码分析的风险 34
2.5 记录/重放:重复计算机运行轨迹 34
2.6 小结 35
第3章 动态分析基础技术 36
3.1 沙箱:简便但粗糙的方法 36
3.1.1 使用恶意代码沙箱 36
3.1.2 沙箱的缺点 37
3.2 运行恶意代码 38
3.3 进程监视器 39
3.3.1 进程监视器的显示 40
3.3.2 进程监视器中的过滤 41
3.4 使用进程浏览器(Process Explorer)来查看进程 43
3.4.1 进程浏览器的显示 43
3.4.2 使用验证选项 44
3.4.3 比较字符串 45
3.4.4 使用依赖遍历器(Dependency Walker) 45
3.4.5 分析恶意文档 46
3.5 使用Regshot来比较注册表快照 46
3.6 模拟网络 47
3.6.1 使用ApateDNS 47
3.6.2 使用Netcat进行监视 48
3.7 使用Wireshark进行数据包监听 49
3.8 使用INetSim 51
3.9 基础动态分析工具实践 52
3.10 小结 55
3.11 实验 56
第2篇 静态分析高级技术篇 60
第4章 x86反汇编速成班 60
4.1 抽象层次 60
4.2 逆向工程 62
4.3 x86体系结构 62
4.3.1 内存 63
4.3.2 指令 64
4.3.3 操作码和字节序 64
4.3.4 操作数 65
4.3.5 寄存器 65
4.3.6 简单指令 67
4.3.7 栈 70
4.3.8 条件指令 73
4.3.9 分支指令 73
4.3.10 重复指令 74
4.3.11 C语言主函数和偏移 76
4.3.12 更多信息:Intel x86 Architecture Manual 77
4.4 小结 78
第5章 IDA Pro 79
5.1 加载一个可执行文件 79
5.2 IDA Pro接口 81
5.2.1 反汇编窗口模式 81
5.2.2 对分析有用的窗口 83
5.2.3 返回到默认视图 83
5.2.4 导航IDA Pro 83
5.2.5 搜索 85
5.3 使用交叉引用 86
5.3.1 代码交叉引用 87
5.3.2 数据交叉引用 88
5.4 分析函数 88
5.5 使用图形选项 89
5.6 增强反汇编 91
5.6.1 重命名位置 91
5.6.2 注释 92
5.6.3 格式化操作数 92
5.6.4 使用命名的常量 93
5.6.5 重新定义代码和数据 94
5.7 用插件扩展IDA 95
5.7.1 使用IDC脚本 96
5.7.2 使用IDAPython 97
5.7.3 使用商业插件 97
5.8 小结 98
5.9 实验 98
第6章 识别汇编中的C代码结构 100
6.1 全局与局部变量 101
6.2 反汇编算术操作 102
6.3 识别if语句 104
6.3.1 用IDA Pro图形化分析函数 105
6.3.2 识别嵌套的if语句 106
6.4 识别循环 107
6.4.1 找到for循环 107
6.4.2 找到while循环 109
6.5 理解函数调用约定 110
6.5.1 cdecl 110
6.5.2 stdcall 111
6.5.3 fastcall 111
6.5.4 压栈与移动 111
6.6 分析switch语句 112
6.6.1 If样式 112
6.6.2 跳转表 114
6.7 反汇编数组 118
6.8 识别结构体 119
6.9 分析链表遍历 121
6.10 小结 123
6.11 实验 123
第7章 分析恶意Windows程序 126
7.1 Windows API 126
7.1.1 类型和匈牙利表达法 126
7.1.2 句柄 127
7.1.3 文件系统函数 127
7.1.4 特殊文件 128
7.2 Windows注册表 129
7.2.1 注册表根键 130
7.2.2 Regedit 131
7.2.3 自启动程序 131
7.2.4 常用注册表函数 131
7.2.5 练习分析注册表操作代码 132
7.2.6 使用.reg文件的注册表脚本 133
7.3 网络API 133
7.3.1 伯克利兼容套接字 134
7.3.2 网络的服务器和客户端 134
7.3.3 WinINet API 135
7.4 跟踪恶意代码的运行 136
7.4.1 DLL 136
7.4.2 进程 137
7.4.3 线程 139
7.4.4 使用互斥量的进程间协作 142
7.4.5 服务 143
7.4.6 组件对象模型 145
7.4.7 异常:当事情出错时 147
7.5 内核与用户模式 148
7.6 原生API 149
7.7 小结 151
7.8 实验 151
第3篇 动态分析高级技术篇 154
第8章 动态调试 154
8.1 源代码级与汇编级的调试器 154
8.2 内核模式与用户模式调试 155
8.3 使用调试器 155
8.3.1 单步调试 155
8.3.2 单步跳过(Stepping-Over)和单步跳入(Stepping-Into) 156
8.3.3 用断点暂停执行 157
8.4 异常 161
8.4.1 首次和二次异常处理 162
8.4.2 常见异常 162
8.5 使用调试器修改可执行文件 163
8.6 修改可执行程序的实践 163
8.7 小结 164
第9章 OllyDbg 165
9.1 加载恶意代码 165
9.1.1 打开一个可执行文件 165
9.1.2 附加调试器到一个运行程序 166
9.2 OllyDbg的接口 167
9.3 内存映射 168
9.3.1 基地址重定位 169
9.4 查看线程和堆栈 170
9.5 执行代码 171
9.6 断点 172
9.6.1 软件断点 173
9.6.2 条件断点 174
9.6.3 硬件断点 175
9.6.4 内存断点 175
9.7 加载DLL 176
9.8 跟踪 177
9.8.1 标准回溯跟踪 177
9.8.2 堆栈调用跟踪 178
9.8.3 运行跟踪 178
9.8.4 跟踪Poison Ivy 178
9.9 异常处理 179
9.10 修补 180
9.11 分析shellcode 181
9.12 协助功能 182
9.13 插件 182
9.13.1 OllyDump 183
9.13.2 调试器隐藏插件 183
9.13.3 命令行 184
9.13.4 书签 185
9.14 脚本调试 185
9.15 小结 186
9.16 实验 187
第10章 使用WinDbg调试内核 189
10.1 驱动与内核代码 189
10.2 安装内核调试 191
10.3 使用WinDbg 193
10.3.1 从内存中读取 194
10.3.2 使用算术操作符 194
10.3.3 设置断点 194
10.3.4 列举模块 195
10.4 微软符号表 195
10.4.1 搜索符号 195
10.4.2 查看结构信息 196
10.4.3 配置Windows符号表 198
10.5 内核调试实践 198
10.5.1 用户空间的代码 198
10.5.2 内核模式的代码 200
10.5.3 查找驱动对象 203
10.6 Rootkit 204
10.6.1 Rootkit分析实践 205
10.6.2 中断 208
10.7 加载驱动 209
10.8 Windows Vista、Windows 7和x64版本的内核问题 209
10.9 小结 210
10.10 实验 210
第4篇 恶意代码功能篇 214
第11章 恶意代码行为 214
11.1 下载器和启动器 214
11.2 后门(backdoor) 214
11.2.1 反向shell 215
11.2.2 远程控制工具 216
11.2.3 僵尸网络 216
11.2.4 远程控制工具与僵尸网络的比较 217
11.3 登录凭证窃密器 217
11.3.1 GINA拦截 217
11.3.2 口令哈希转储 218
11.3.3 击键记录 221
11.4 存活机制 223
11.4.1 Windows注册表 223
11.4.2 特洛伊木马化(Trojanized)系统二进制文件 225
11.4.3 DLL加载顺序劫持 227
11.5 提权 228
11.5.1 使用SeDebugPrivilege 228
11.6 隐藏它的踪迹——用户态的Rootkit 229
11.6.1 IAT Hook 230
11.6.2 Inline Hook 231
11.7 小结 232
11.8 实验 232
第12章 隐蔽的恶意代码启动 234
12.1 启动器(Launcher) 234
12.2 进程注入 234
12.2.1 DLL注入 235
12.2.2 直接注入 237
12.3 进程替换 238
12.4 钩子(Hook)注入 240
12.4.1 本地和远程钩子(Hook) 240
12.4.2 使用钩子的击键记录器 241
12.4.3 使用SetWindowsHookEx 241
12.4.4 目标线程 241
12.5 Detours 242
12.6 APC注入 243
12.6.1 用户模式下APC注入 244
12.6.2 内核模式的APC注入 245
12.7 小结 246
12.8 实验 246
第13章 数据加密 248
13.1 分析加密算法的目的 248
13.2 简单的加密算法 248
13.2.1 凯撒密码 249
13.2.2 XOR 249
13.2.3 其他一些简单的加密策略 254
13.2.4 Base64 255
13.3 常见的加密算法 258
13.3.1 识别字符串和导入 259
13.3.2 查找加密常量 259
13.3.3 查找高熵值内容 261
13.4 自定义加密 262
13.4.1 识别自定义加密 263
13.4.2 攻击者使用自定义加密的优势 265
13.5 解密 265
13.5.1 自解密 265
13.5.2 手动执行解密函数 266
13.5.3 使用通用的解密规范 267
13.6 小结 270
13.7 实验 271
第14章 恶意代码的网络特征 273
14.1 网络应对措施 273
14.1.1 在原始环境中观察恶意代码 273
14.1.2 恶意行为的痕迹 274
14.1.3 OPSEC=操作安全性 275
14.2 安全地调查在线攻击者 275
14.2.1 间接性策略 275
14.2.2 获取IP地址和域名信息 276
14.3 基于内容的网络应对措施 278
14.3.1 使用Snort进行入侵检测 278
14.3.2 深入观察 279
14.4 结合动态和静态分析技术 282
14.4.1 过度分析的危险 283
14.4.2 在众目睽睽下隐藏 283
14.4.3 理解周边代码 286
14.4.4 寻找网络操作代码 287
14.4.5 了解网络内容的来源 288
14.4.6 硬编码数据vs.临时数据 289
14.4.7 确定和利用编码步骤 289
14.4.8 创建特征 291
14.4.9 分析解析例程 292
14.4.10 针对多个元素 294
14.5 了解攻击者的意图 295
14.6 小结 296
14.7 实验 296
第5篇 逆向工程 300
第15章 对抗反汇编 300
15.1 何谓对抗反汇编技术 300
15.2 挫败反汇编算法 301
15.2.1 线性反汇编 302
15.2.2 面向代码流的反汇编 303
15.3 对抗反汇编技术 306
15.3.1 相同目标的跳转指令 306
15.3.2 固定条件的跳转指令 307
15.3.3 无效的反汇编指令 308
15.3.4 用IDA Pro对指令进行NOP替换 311
15.4 混淆控制流图 312
15.4.1 函数指针问题 312
15.4.2 在IDAPro中添加代码的交叉引用 313
15.4.3 滥用返回指针 313
15.4.4 滥用结构化异常处理 315
15.5 挫败栈帧分析 317
15.6 小结 320
15.7 实验 320
第16章 反调试技术 322
16.1 探测Windows调试器 322
16.1.1 使用Windows API 322
16.1.2 手动检测数据结构 324
16.1.3 系统痕迹检测 326
16.2 识别调试器的行为 327
16.2.1 INT扫描 327
16.2.2 执行代码校验和检查 328
16.2.3 时钟检测 328
16.3 干扰调试器的功能 330
16.3.1 使用TLS回调 330
16.3.2 使用异常 332
16.3.3 插入中断 333
16.4 调试器漏洞 334
16.4.1 PE头漏洞 334
16.4.2 OutputDebugString漏洞 336
16.5 小结 336
16.6 实验 336
第17章 反虚拟机技术 338
17.1 VMware痕迹 338
17.1.1 绕过VMware痕迹的探测 340
17.1.2 探测内存痕迹 342
17.2 查找漏洞指令 342
17.2.1 使用Red Pill反虚拟机技术 343
17.2.2 使用No Pill技术 344
17.2.3 查询I/O通信端口 344
17.2.4 使用str指令 345
17.2.5 反虚拟机的x86指令 346
17.2.6 在IDAPro中高亮显示反虚拟机代码 347
17.2.7 使用ScoopyNG 347
17.3 调整设置 348
17.4 虚拟机逃逸 349
17.5 小结 349
17.6 实验 349
第18章 加壳与脱壳 352
18.1 剖析加壳 352
18.1.1 脱壳存根 353
18.1.2 加载可执行文件 353
18.1.3 解析导入函数表 353
18.1.4 尾部跳转 354
18.1.5 图示脱壳过程 354
18.2 识别加壳程序 355
18.2.1 加壳程序的标识 355
18.2.2 熵计算 356
18.3 脱壳选项 356
18.4 自动脱壳 356
18.5 手动脱壳 357
18.5.1 使用导入重构器重构导入表 358
18.5.2 查找OEP 359
18.5.3 手动修复导入表 363
18.6 常见壳的技巧与窍门 364
18.6.1 UPX 364
18.6.2 PECompact 365
18.6.3 ASPack 365
18.6.4 Petite 365
18.6.5 WinUpack 366
18.6.Themida 367
18.7 不完全脱壳情况下的分析 368
18.8 加壳DLL 368
18.9 小结 369
18.10 实验 369
第6篇 高级专题 372
第19章 shellcode分析 372
19.1 加载shellcode进行分析 372
19.2 位置无关代码 373
19.3 识别执行位置 373
19.3.1 使用call/pop指令 374
19.3.2 使用fnstenv指令 376
19.4 手动符号解析 377
19.4.1 在内存中找到kernel32.dll 378
19.4.2 解析PE文件导出数据 380
19.4.3 使用散列过的导出符号名 382
19.5 一个完整的Hello World例子 383
19.6 shellcode编码 385
19.7 空指令雪橇 387
19.8 找到shellcode 387
19.9 小结 388
19.10 实验 389
第20章 C++代码分析 391
20.1 面向对象的编程语言 391
20.1.1 this指针 392
20.1.2 重载与修饰 394
20.1.3 继承(Inheritance)和函数重写(Overriding) 395
20.2 虚函数和非虚函数 396
20.2.1 虚函数表的使用 398
20.2.2 识别虚函数表 399
20.3 创建和销毁对象 400
20.4 小结 401
20.5 实验 401
第21章 64位恶意代码 403
21.1 为什么需要64位恶意代码 403
21.2 x64架构上的差别 404
21.2.1 x64调用约定和栈使用上的差别 406
21.2.2 64位异常处理 408
21.3 在Windows 64位上的Windows 32位 408
21.4 恶意代码功能上的64位提示 409
21.5 小结 410
21.6 实验 410
附录A常见Windows函数列表 412
附录B流行的恶意代码分析工具列表 424
附录C实验作业参考解答 435
附录D致青春,基础软件开发的中国故事 691
附录E Syser操作入门 695