# 0x00 安全素养
# 网络安全法
不要违法,不要违法,不要违法。
参考资料:
https://baike.baidu.com/item/ 中华人民共和国网络安全法
# 0x01 基础
编程和逆向工程的能力是相当重要的。
# 编程语言功底
精通 C 语言(指针、函数)、C++
汇编语言(熟悉常见指令及寄存器等,能够熟练阅读汇编代码)
熟练使用 python
# 逆向功底 & 底层原理
IDA PRO 的使用(或者 Ghidra 等其它工具)
gdb 的基本使用(断点、单步、查看内存等)
- 《程序员的自我修养》
- 程序的编译链接原理
- 内存管理
- 进程地址空间
- 函数调用惯例
- …
- …
# 0x02 二进制安全
# CTF
https://ctf-wiki.org/
先从 CTF 入手,学习各种漏洞类型及利用手法,不断刷题、阅读,大一大二专注在 CTF 比赛中,要求能够解决大部分常规难度的题目。
学习新的题目时,不要先看 wp,要先自己去找漏洞,找漏洞是最重要的,漏洞的利用上可以跟着 wp 一步一步调试。
这里有一些刷题平台:
- https://buuoj.cn/
- https://ctf.bugku.com/
- https://www.ctfhub.com/#/index
- https://adworld.xctf.org.cn/
- https://pwnable.tw/
# PWN
# 配置环境
CTF 中接触到的 PWN 题大多属于 LINUX PWN,给电脑装 LINUX 系统比较麻烦,一般情况下是装虚拟机。
如果想跳过配置环境这一步,可以直接使用 KALI LINUX,但还是建议自己装一次环境(日后可能会需要下载安装一些工具,需要会 LINUX 系统的操作)。
可以参考我的另一篇文章:
pwn环境搭建
# 基本工具
# 逆向辅助类
IDA PRO
IDA PRO 是一款很好用的反汇编工具,其反编译插件在很多时候能够将代码还原到接近源码的水平,但是 IDA 的使用比较复杂,需要自己学习。
链接:https://pan.baidu.com/s/1ZN8Kd2QbpnP5qm1QBfxaIA
提取码:j2myGDB
GDB 是一款功能强大的程序调试工具,是动态调试必不可少的工具,可以很方便的查看堆中链表的状态,各个地址的内容。GDB 拥有多个插件(peda、pwndbg、gef 等)这些插件提供了一些额外的命令,在可视化和功能上都进行了扩展。
推荐安装一个插件即可,多个插件的切换与系统环境变量相关,自行百度。
# 漏洞利用类
这一类工具几乎都可以在 GITHUB 上下载。
pwntools
pwntools 是一个 CTF 框架和漏洞利用开发库,涵盖了 pwn 题利用脚本所需要的各种工具。包括方便的 IO 交互函数,ROP、格式化字符串等利用的自动化工具,shellcode 生成器等等,是目前最好用也是仅有的大型 pwn 利用框架。能节省大量编写脚本的时间。
ZIO
ZIO 是一个专门为 CTF PWN 开发的 Python 库,基于 ZIO 可以方便实现对远程服务器上的服务程序进行数据读写操作,也支持对本地程序的数据读写操作。
ROPgadget
ROP 是一种高级的内存攻击技术,常用来绕过现代操作系统的各种通用防御。Ropgadget 用于找寻程序中用来组装 ROP 链的 gadget。
checksec
查询程序架构和保护机制的开启状况。
one_gadget
分析定位 libc 中获取 shell 的地址,在满足特定条件的情况下,仅拥有该地址就可以 get shell。而非手动输入 /bin/sh 和 system 的地址。
seccomp-tools
分析程序中的 seccomp 安全机制开启的具体情况。
...
# 保护机制
# 系统选项
ASLR:地址空间随机化 (系统选项)
ASLR 有三个等级,对应系统文件中的三个值。
0:关闭 ASLR。
1:mmap base、stack、vdso page 将随机化,“.so” 文件会被加载到随机地址,程序的代码段加载地址将被随机化。
2:在 1 的基础上增加了 heap 随机化。
ASLR 保证每次程序加载的时候自身和所加载的库文件都会被映射到虚拟地址空间的不同地址处。
# 编译选项
NX:堆栈不可执行
主要防止程序直接在非可执行的内存区(堆和栈)上运行 shellcode 代码。
PIE:程序基地址随机化
程序每个段加载出来的基地址都是随机化的。
RELRO:重定位
一般分为 partial relro 和 full relro 两种情况,前者重定位信息可写(如 GOT 表),后者不可写。
STACK CANARY:栈溢出保护
在栈的缓冲区和控制信息(如 EBP 等)间插入一个 canary word。这样,当缓冲区被溢出时,在返回地址被覆盖之前 canary word 会首先被覆盖。通过检查 canary word 的值是否被修改,就可以判断是否发生了溢出攻击,从而保护程序因为栈溢出而被攻击。
# 常见漏洞
# 栈相关漏洞
学习栈相关漏洞首先要对程序栈的结构,调用机制,以及函数参数传递规则(函数参数入栈出栈顺序)有一定了解。
栈溢出
指栈上的缓冲区被填入了过多的数据,超出了边界,从而导致栈上原有的数据被覆盖,如果能让指定内容覆盖到某些位置,就能 get shell,通常覆盖栈的局部变量、bp(函数栈栈底指针)、ip(程序返回地址)。
关于栈溢出有几个需要学习的点:
当开启 NX 和 CANARY 后如何执行栈溢出。
覆盖 ip:ip 存放的是返回到父函数调用处的下一个位置,如果通过栈缓冲区用某一地址 a 覆盖了 ip,在该函数结束后,会跳转到 a 地址上,从而劫持控制流。
覆盖栈中存储的临时变量:在知道两个变量地址偏移时,可以通过一个变量覆盖另一个变良,从而改变另一个变量。
关注一些敏感函数:这些函数能够产生缓冲区溢出,从而实现栈溢出。
常见的漏洞函数:
- gets(buff)
- scanf("%s",buff)
- ...
潜在的漏洞函数:
- read
- strcpy
- memcpy
- ...
# 栈相关漏洞的利用
栈的特殊利用
libc 信息泄露:main 函数栈底存放了返回地址,如果能泄露改返回地址,就能计算出 libc 的基址,从而得到其他函数地址。
通过 libc 泄露栈地址:在已知 libc 地址的情况下,可以根据 libc 中的 Environ 偏移来计算栈的偏移,从而计算出栈的地址。
往栈上写 ROP
环境变量修改
多级指针
栈喷射
在 ROP 时无法找到确定的栈地址,便预先在栈中布置大量重复的 ROP 数据块,只要在返回时位于其中一个数据块就能实现 ROP。
并非必须是 ROP,shellcode、ROP 地址等数据也可以利用栈喷射。
栈迁移
溢出的长度太短,尝试改变 sp 和 bp 寄存器的值,在新一段地址上建立栈并写入 rop 链
线程栈
现阶段了解一下即可。
# 堆相关漏洞(堆漏洞是 CTF 比赛重点)
堆主要指用户动态申请的内存(如调用 malloc、alloc、alloca 等函数)。
学习堆相关漏洞需要了解:
堆基本数据结构 chunk(alloced chunk、free chunk、top chunk)。
堆空闲块管理结构 bin(fast bin、unsorted bin、small bin、large bin)。
malloc、free 函数的基本规则,建议结合源码对照分析。
tcache 机制(很重要)。
常规堆溢出
与栈溢出类似,在堆上的缓冲区被填入了过多的数据,超出了边界,导致堆中原有的数据被覆盖。通常有以下两种情况:
- 覆盖本堆块内部数据:通常发生在结构体内部,如结构体中数组溢出,就会覆盖后续变量。
- 覆盖后续堆块数据:不仅影响后续堆块的数据,还破坏了堆块的结构。
第一种情况,参照栈溢出即可。
第二种情况,有其他利用方法。
Off By One
相比于常规的堆溢出,Off By One 只能溢出一字节,在 CTF 比赛中,Off By One 通常位于堆块末尾,溢出的一字节恰好能够覆盖下一堆块的 size 域的最低位,Off By One 本身比较难以利用,通常用来触发 Unlink。
Use After Free(UAF)
UAF 即释放后使用漏洞,当堆指针在释放后为被置 NULL,就会形成悬挂指针,在下一次访问该指针时,仍然能够访问到原指针所指向的堆内容。UAF 的利用需要具体问题具体分析,来确定其是否能泄露信息或修改信息。
Double Free
Double Free 主要指对指针存在多次释放的情况,算是 UAF 中比较特殊的一种,针对用于释放堆块的函数。对此释放能够使堆块发生重叠,前后申请的堆块可能会指向同一块内存。还可以构造特殊的堆结构,从而运用针对堆结构的利用方法。
IO_FILE
IO_FILE 本身并不是漏洞,而是程序执行 fopen 等函数时创建的结构体。在出现 House Of Orange 后,陆续出现了利用 IO_FILE 进行攻击的手法
- FSOP
- Vtable 劫持
- 利用缓冲区指针达成任意读写
- …
# 堆相关漏洞的利用
Unlink
Unlink 是把 free 掉的堆块从所属的 bins 链中,卸下来的操作。它是在 free 掉一块 chunk (除 fastbin 的 chunk 外)之后,glibc 检查这块 chunk 相邻的上下两块 chunk 的 free 状态之后,做出的堆块合并引起的。
Unlink 攻击指的是先伪造堆块,在 free 操作时触发堆块合并,在绕过一系列检测机制后,就可以通过伪造的堆块修改其他堆块的指针,或者实现任意地址写。
Fastbin Attack
Fastbin Attack 主要针对 fastbin 的使用和释放机制,对 fastbin 的间接利用比较多。
直接利用 fastbin 的方法主要是针对 fastbin 的单链表结构,更改其后续指针,控制 fastbin 在下次所要分配的堆块。
House Of Orange
使用 Unsorted Bin Attack 修改 IO_list_all 来获取 shell。
学习 House Of Orange 需要理解两个概念 ——Unsorted Bin Attack 和 FSOP。
Large bin attack
覆盖 largebin 中 bk_nextsize 指针,在 largebin 插入 unsorted bin 时,可以做到往任意地址写一个堆地址的效果
堆喷射
堆喷射主要指在堆块中布置好大量重复性的数据,便于目的地址索引到堆上的数据,与栈喷射相似但更为麻烦,在真实漏洞中利用较多,而在 CTF 比赛中不常出现。
# 格式化字符串漏洞
格式化字符串漏洞主要是针对一些格式化函数(printf、sprintf、vsprintf 等)。这些格式化函数利用格式化字符串来指定串的格式。下面给出四个比较关键的格式符:
% x(% lx):替换为参数的值(十六进制)。
% p:替换为参数的值(指针形式)。
% s:替换为参数所指向内存的字符串。
% n:将格式化串中该特殊字符之前的字符数量写入参数中(获取地址的参数)。
同时还要了解参数定位。
例如:printf ("% p,% x",&a,&b); 其中的 % p 和 % x 对应第 1、2 个参数。
也可以使用 "% d$m" 的形式来定位参数列表中第 d 个参数(从 1 开始);其中 m 是前面所说的格式符(x、p、s、n 等)。
# 格式化字符串的利用
格式化函数遇到格式符的关键字符后,会按照传参规则去寻找参数来进行替换或修改。如果实际参数数量小于所需参数数量,依然会将对应位置的数值当成参数进行转换,从而触发格式化字符串漏洞。
任意地址读
通过前面所说的参数定位 “% d$m”,在确定所需信息在栈中的位置(位于第几个参数),通过参数定位可以将该信息泄露出来。
任意地址写
主要是利用格式化字符串中的 % n 对参数进行写入,写入的值是格式化字符串中 % n 之前的字符数量。
% n 修改 4 字节、% hn 修改 2 字节、% hhn 修改 1 字节。
可以结合 % c 来修改成特定的值,例如 "%100c" 会替换为宽度为 100 的字符。
# 整型漏洞
整型漏洞主要指发生在整型数据上的漏洞,整型溢出指试图保存的数据超过整型数据的宽度时发生的溢出。
宽度溢出
整型数据在计算机中的存储一般按字节进行存储,不同的整型数据所需要的字节数也不同,“所需要的字节数” 就是该整型数据的宽度,如果数据所要表达的值大于这个宽度就会发生宽度溢出。
宽度溢出主要出现在:
整型数据运算
整型数据赋值
...
符号转换
符号转化通常用于:
- 将无符号数和有符号数进行强制转换后数值相差过大,从而绕过条件判断。
- 有些函数对参数有特定要求,但使用时并没有严格按照参数的类型进行参数传递。
数组越界
由于检查不严格,导致在对数组内存的索引时超出了数组的预设范围,从而访问到其他数据。
如果可以显示数组内容,就可以实现信息泄露;如果可以修改数组内容,就可以实现信息修改。
# 逻辑漏洞
逻辑漏洞主要指程序逻辑上出现的问题,当程序逻辑不严密或者逻辑太复杂,就会导致一些逻辑分支不能正常处理或处理错误。在 PWN 题中较少出现,主要是竞态条件漏洞。
竞态条件漏洞
竞态条件漏洞是指多任务(多进程、多线程等)对同一资源进行访问时,因访问资源的先后顺序不同产生冲突的情况,通过竞态条件漏洞可以实现越权访问、资源篡改等操作。
# 其他平台漏洞
- IOT 漏洞
- 虚拟机漏洞
- 内核漏洞
- ...
# REVERSE
Reverse 即软件逆向工程,是对编译成型的二进制程序进行代码、逻辑和功能分析的过程。在 CTF 中主要考察软件静态分析和动态调试能力,常见的逆向目标为 Windows、Linux 平台下 x86、x64 二进制可执行程序。
# 能力要求
- 熟悉如操作系统,汇编语言,加解密等相关知识。
- 具有丰富的多种高级语言的编程经验。
- 熟悉多种编译器的编译原理。
- 较强的程序理解和逆向分析能力。
# 逆向分析的主要方法
静态分析法
静态分析法是在不执行代码文件的情况下,对代码进行静态分析的一种方法,主要观察代码文件的外部特性,包括文件类型分析和静态反汇编、反编译。通常使用反汇编工具查看内部代码,分析代码结构。
动态分析法
动态分析法是在程序文件的执行过程中对代码进行动态分析的一种方法,其通过调试来分析代码、获取内存的状态等,目的在于定位关键代码后,在程序运行的过程中,借由输出信息(寄存器,内存变化,程序输出)等来验证自己的推断或是理解程序功能。通常使用调试器来分析程序的内部结构和实现原理。
# 汇编指令体系结构
逆向分析的程序所使用的处理器架构通常为 Intel 架构,所以需要对 Intel x86 和 x64 指令体系有所了解,包括:
- x86 指令体系下:
- 寄存器组
- 汇编指令集
- 数据传送类指令
- 栈操作与函数调用
- 算数、逻辑运算指令
- 控制转移指令
- 特殊指令
- x86 应用程序二进制接口
- x64 指令体系下与 x86 指令体系相似,这里主要标注不同点:
- 寄存器组
- 系统调用指令
- x64 应用程序二进制接口
# 基本工具
# 反汇编和反编译工具
反汇编工具有很多,但最推荐的是 IDA PRO,在反编译方面,IDA 自带的 Hex-Ray 反编译插件也是最好的。
IDA 的使用比较复杂,需要自己学习。
链接:https://pan.baidu.com/s/1ZN8Kd2QbpnP5qm1QBfxaIA
提取码:j2my
# 调试工具
调试工具有以下两个重要功能:
断点设置
允许用户选在程序中任意位置的某行代码,一旦程序运行到这一行,将知识调试工具停止运行程序,并显示程序的当前状态。
代码跟踪(单步调试)
允许用户在程序运行时跟踪他的执行,程序每执行一条汇编代码后都会暂停,允许用户观察甚至改变程序的状态。
调试工具主要根据操作系统来选择
Windows——Ollydbg
Ollydbg 是 Windows 下一款具有可视化界面的用户态调试工具,推荐从吾爱破解论坛上下载吾爱破解专用版 Ollydbg,这个版本有对抗反调试的功能。
Linux——GDB
GDB 是一款功能强大的程序调试工具,是动态调试必不可少的工具,可以很方便的查看堆中链表的状态,各个地址的内容。GDB 拥有多个插件(peda、pwndbg、gef 等)这些插件提供了一些额外的命令,在可视化和功能上都进行了扩展。
推荐安装一个插件即可,多个插件的切换与系统环境变量相关,自行百度。
# Trace 类工具
Trace 类工具通过一定的方式监控并记录程序的运行,然后使分析者在记录的信息中得到程序的一些动态信息。
Strace
Strace 使 Linux 下一个用来跟踪系统调用的工具,可以监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。
Qira
Qira 是一个强大的 Trace 类工具,可以将程序整个执行流全部记录下来,然后给予用户回溯、查看命中断点的所有指令(即交叉引用)等。
Qira 的安装比较难,多多百度 / 谷歌。
# 常规逆向分析流程
# 1、收集信息
使用 strings/file/binwalk/IDA 等静态分析工具收集信息,并根据这些静态信息进行 google/github 搜索
# 2、干扰分析技术
程序为了保护代码,通常会使用一系列技术来干扰逆向分析,这里会介绍一些常见的干扰分析技术。
花指令
花指令是代码保护中一种简单的技巧,原理是在原始代码中插入一段无用的或者能够干扰反汇编引擎的代码。花指令主要影响静态分析,在 IDA 中表现为一些指令无法识别,导致某些函数未能识别,从而无法对这些函数进行反编译。
要破解花指令,可以在 IDA 中手动将花指令 patch 成 nop 空指令,从而去除花指令。如果程序中花指令较多,可以通过分析花指令的特定模式,编写 IDAPython 脚本对花指令进行自动化搜索和 patch。
反调试
反调试技术是指程序在运行时会检测其是否处于被调试状态,如果发现其正在被调试,就无法正常运行。
Windows 下通过 Ollydbg 的 StringOD 插件可以过滤掉大多数的反调试方法。
Liunx 下主要利用 ptrace 系统调用、proc 文件系统检测和父进程检测来检测自身是否正在被调试,针对这些反调试方法,常用的方法就是定位到反调试的代码,然后对程序进行 patch,在不影响程序正常功能的情况下,跳过对调试器的检测代码。
加壳
加壳是指在二进制的程序中植入一段代码。在运行的时候优先取得程序的控制权,这段代码会在执行的过程中对原始指令进行解密还原,之后再将控制权交还给原始代码,执行原来的代码。
被加过壳的程序,其真正的代码是加密存放在二进制文件中的,只有在执行时才从内存中解密还原出来,因此没法对加了壳的程序直接进行静态分析。
在 CTF 比赛中出现的带壳程序通常为已知的壳,大部分都可以通过使用专用工具或者脚本的脱壳。
可以使用 PEiD 工具查询该带壳程序用的什么壳,再用对应工具或脚本脱壳。
控制流混淆
对于控制流混淆的程序,没有办法直接进行静态分析,也无法进行反编译,而调试器调试也会陷入控制流的跳转混乱中。
对于控制流混淆的程序,通常通过 Trace 工具记录下程序运行的所有指令,然后再运行这些指令的基础上进行数据流分析。
双进程保护(Debug Blocker)
双进程保护是一种在调试模式下运行自身程序的方法。这种保护通常存在两个进程,由父进程调试子进程。实际功能的代码运行在子进程中,但是因为子进程已经处于调试状态,无法再使用其他调试器进行附加操作。同时父进程能够控制子进程,通过处理子进程的异常,可以控制子进程正常运行。
双进程保护技术的难点在于,真正的功能运行在子进程中,若要调试子进程,就需要断开其与父进程之间的链接,但是一旦断开,没有父进程处理子进程的异常,会导致子进程无法正常运行。
对于双进程保护的程序,其父进程通常功能单一,因此先针对父进程,了解其处理子进程异常的逻辑,然后调试子程序,使其脱离父进程之后仍能正常运行,最后在对子进程进行调试分析。
# 3、关键代码定位
在一个可执行程序中,汇编代码数量庞大,所以要能够定位出真正需要分析的关键代码,只有找到关键代码之后,才能对关键代码采用的算法进行分析,理清程序功能,最后针对程序功能,写出对应脚本,解出 flag。
这里给出 3 个常用的关键代码定位法
API 断点法
例如:在获取文本输入时,窗口类程序获取文本的方式主要是通过 GetWindowsText 和 GetDlgItemText 两个 API 来获取。在输出结果时,会弹出对话框,这时调用的 API 通常为 MessageBox。在这些 API 函数中下断点,在调试工具中断下来后,通过栈回溯即可定位到关键代码。
字符串检索法
在 IDA 中
打开 Strings 子窗口,通过 Ctrl+F 输入想要查找的字符串。
在 Ollydbg 中
通过 Alt+E,可以查看可执行模块,找到主模块,点击右键,选择中文搜索引擎,根据需要搜索 ASCII 或者 UNICODE。
辅助工具定位法
针对特定语言或编译器生成的程序,可以用一些辅助工具帮助快速定位案件处理程序的地址。
如:针对 MFC 程序的 xspy,针对 Delphi 程序的 Dede。
# 4、常见加密算法识别
在对数据进行变换时,通常会使用一些常用的加密算法,如果能够快速识别出对应的加密算法,就能更快的分析出整个完整的算法,下面给出 CTF 比赛中常用的几种加密算法。
base64
base64 将输入中的每 3 字节(24 比特)按每 6 比特分成一组,编程 4 个小于 64 的索引值,然后通过一个索引表得到 4 个可见字符。
索引表为一个 64 字节的字符串:
“ABCDEFGHIJKLMNOPQRSTUVMXYZabcdefghijklmnopqrstuvwxyz0123456789+/”
如果在代码中发现引用了这个索引表,基本可以确定是 base64。此外,还有一些变种的 base64,主要是改变了索引表。
TEA
TEA 算法是一种常见的分组加密算法,密钥为 128 比特位,明文为 64 比特位,主要做了 32 轮变换,每轮变换都涉及移位和变换。
在 TEA 算法中有一个固定的常数 0x9e3779b9 或者 0x61x88647。
如果在加密函数中发现了这个常数,基本可以确定是 TEA。
AES
AES 是一种常见的分组加密算法,加密过程涉及 4 种操作:字节替代、行移位、列混淆、轮密钥加。其中字节替代过程是通过 S 盒完成一个字节到另一个字节的映射。(S 盒的结构自行百度)
如果发现程序中有 S 盒或者动态生成了 S 盒,基本可以确定是 AES。
RC4
RC4 算法属于流加密算法,包括初始化函数和加解密函数。其中初始化代码对某一字符数组进行了初始化赋值,且赋值分别递增,之后又对数组进行了 256 次交换操作。
通过识别初始化代码,可以判断是否为 RC4。
MD5
MD5 信息摘要算法,是一种广泛使用的密码散列函数,会产生一个 128 位(16 字节)的散列值。
MD5 加密算法中有个初始化函数 MD5Init (),会初始化四个 MD5 链接变量的整型参数。分别为 0x67452301、0xefcdab89、0x98badcfe、0x10325476,当看到这四个常数,就可以怀疑是 MD5。
# 5、求解 flag
直接从内存获取
一些比较简单的题目可以直接查看内存来获取 flag,这种题目只需要在特定的地方下断点,然后查看内存即可获得 flag。
对算法进行逆变换操作
这类题目要根据程序的输出结果,再分析程序的加密算法,然后编写出对应的逆算法得到 flag。
线性变换的求解
如果加密算法是一个线性变换,output 的第 i 位只能由 input 的第 i 位决定,通过获取 input [i] 的所有可能输入对应的输出 output [i],即可求出 input [i],对于这种变换,可以进行单字符爆破。
约束求解
如果在 output=convert (input) 之后,需要 output 满足多个约束条件,这种情况下就属于约束求解。
通常会用到的约束求解器为 z3。
# 小结
- 使用 strings/file/binwalk/IDA 等静态分析工具收集信息,并根据这些静态信息进行 google/github 搜索。
- 研究程序的保护方法,如代码混淆,保护壳及反调试等技术,并设法破除或绕过保护。
- 反汇编目标软件,快速定位到关键代码进行分析。
- 结合动态调试,验证自己的初期猜想,在分析的过程中理清程序功能。
- 针对程序功能,写出对应脚本,求解出 flag。
# 实战 & 进阶
一般情况下,大一、大二通过 CTF 比赛学习相应技术,大三开始接触实战。
根据自己的积累和兴趣,可选取一个方向去深入,例如文件媒体解析类、内核、浏览器内核、IOT、移动端等等。
下面是一些实战 & 进阶 & 提升的方式
复现漏洞
学习漏洞挖掘技术(fuzz)
关注顶会议题,尝试寻找攻击面去实践漏洞挖掘
- blcak hat
- poc
安全研究漏洞分析
甲方
- 对内漏洞挖掘
- 安全攻防
病毒分析
纯逆向
移动安全、安全加固(移动端)
游戏安全