% !Mode:: "TeX:UTF-8" \chapter{示例:实现方案} 本章首先介绍了本系统实现的设计原则与目标,然后描述了系统的整体架构与总体设计方案,接着阐述了系统的各个模块实现时的解决方案,最后给出了系统在~Android~具体实现时的实现方法和使用说明。 \section{设计目标与原则} \subsection{设计目标} 本系统能够检测已知恶意软件及其变种,并能通过模糊检测发现具有相似恶意行为的未知恶意软件,为~Android~平台这样的开放式移动平台提供安全保障,可广泛用于各种型号的~Android~设备。系统具体设计目标如下: \begin{enumerate} \item 适用于目前主流的~Android~平板及手机,至少可运行于3.0版本系统。 \item 能够检测用户指定的程序是否为恶意程序。 \item 能够自动检测设备上的所有程序,并可定时检测。 \item 能够监控设备的程序安装行为,自动检测安装的程序是否为恶意程序。 \item 能够保证本程序自身的特征库不被破坏,并能及时修复和更新特征库。 \item 能够保证用户使用方便。 \end{enumerate} \subsection{设计原则} 从安全产品的特点出发,本系统设计与实现将遵循下列一些设计原则: \begin{enumerate} \item 高效性 系统运行效率高,可快速实现对目标程序的特征提取与检测,并将结果用最清晰简洁的方式告知用户。 \item 灵活性 为用户提供的各种功能具有可选性,用户可根据自己的需要选择其中的功能,而且用户可自行决定如何处理检测结果为恶意的程序。 \item 实用性 本系统应按照实用性原则进行设计,在保证对程序检测的同时,力求用户界面简洁友好。 \item 可扩展性 目前本系统只检测程序的~Java~实现部分,但是还有极少数程序代码是用~C~语言编写的,在后续的开发过程中,可以在不改变程序结构的前提下,实现这一部分的检测功能。 \item 健壮性 \par 系统应具有应对非法操作的能力,并且当针对于本系统的恶意攻击到来时,可以及时防御,防止自身特征库遭到损坏。 \end{enumerate} \section{系统方案} 本系统由两部分构成,第一部分是产品部分,即~Android~应用程序,采用~Java~作为编程语言。第二部分是检测算法模型构建部分,采用~Matlab~实现,其输出的模型数据供产品部分作为特征库使用。故本系统的特征库构建于~PC~端,而对目标程序的检测运行于~Android~端。从而将构建过程中包含的巨大计算量留在~PC~端。其具体结构如图~\ref{system}~所示。 \pic[htbp]{系统结构}{height=5.86cm}{system} 其中程序信息抽取模块是本系统检测恶意软件的基础,特征检测模块是系统的核心与实现难点。特征检测模块中又分为变种检测模块和模糊检测模块,变种检测模块检测待检软件是否是已知恶意软件的变种,而模糊检测模块实现的是本系统从人脸匹配中引入的新型检测手段,可对特征库中不存在的未知恶意软件进行检测。 \section{系统模块的实现} \subsection{程序分解模块} Android~的程序文件为~APK~格式,APK~文件是~Android~最终的运行程序,是~Android~Package~的全称。类似于~Symbian~ 操作系统中~sis~文件,APK~文件其实是~Zip~文件格式,但后缀名被修改为~APK。通过解压,可以看到~Dex~ 文件。Dex~是~Dalvik~VM~executes~的全称,即~Dalvik~虚拟机可执行文件,并非~Java~ME~的字节码而是~Dalvik~字节码。\\ 一个APK文件结构为: \begin{enumerate} \item META-INF$\backslash$————签名信息,用来保证~apk~包的完整性和系统的安全,jar~文件经常可以看到; \item res$\backslash$————资源文件夹,包括程序中使用的图片,布局文件等; \item AndroidManifest.xml$\backslash$————项目配置清单,但不是明文的XML格式,无法直接打开阅读; \item classes.dex$\backslash$————Dalvik~可执行二进制文件,在运行时被动态优化为dey文件并由Dalvik虚拟机解释执行 ; \item resources.arsc$\backslash$————编译后的二进制资源文件,资源文件打包而成,字符串值(源码中的/value/Strings.xml)就在其中; \item lib$\backslash$————动态链接库文件; \item assets$\backslash$————原始文件文件夹,其中的文件不会被压缩,也不能像~res~目录下的资源文件一样通过资源类引用。 \end{enumerate}\par 图~\ref{apk}~是我们解压缩helloworld.apk文件后看到的内容,可以看到其结构跟工程结构有些类似。 \pic[htbp]{helloworld.apk的结构}{width=0.5\textwidth}{apk} classes.dex~文件是~Java~源码编译后生成的~Java~字节码文件。但由于~Android~使用的~Dalvik~虚拟机与标准的~Java~虚拟机是不兼容的,Dex~文件与~Class~文件相比,不论是文件结构还是~opcode~都不一样。目前常见的~Java~ 反编译工具都不能处理~Dex~文件。Android~SDK~中提供了一个~Dex~文件的反编译工具~dexdump。用法为,dexdump -d -f -h xxx.dex。 \\ 指令参数解释:\\ -d : 反编译程序段\\ -f : 从文件头显示摘要信息\\ -h : 显示文件头详情\\ -C : 反编译低级符号名\\ -S : 只计算大小 \par 在知道了程序安装包是~Zip~编码之后,我们就可以通过遍历~Zip~包中包含的项目名,找到程序的二进制文件,即~Dex~文件。并在内存中建立一段缓冲区,可将~Dex~文件读入内存,再写到指定的临时文件中。分解流程如图~\ref{flow1}~所示。 \pic[htbp]{程序分解流程}{height = 5.76cm}{flow1} \subsection{构建特征向量模块} 特征向量是数据挖掘中的一个概念,一个数据集中的每个数据实例都可以用一组属性值来描述,每一个数据实例都具有一个特殊的目标属性,称为类属性,它表征每个数据实例归属的类。这一组属性值即是代表这个数据实例的特征向量。在我们的检测问题中,Android~系统~API~和~Java~标准函数就是我们定义的属性,而恶意和非恶意就是类属性。这一过程如图~\ref{flow3}~所示。 \pic[htbp]{构建特征向量流程}{height = 0.5\textwidth}{flow3} 我们将特征向量空间($\Omega$)存储在数据库中,数据表的定义见表~\ref{omegatable}~所示。 \threelinetable[htbp]{omegatable}{0.8\textwidth}{llllX}{$\Omega$~数据表定义} {字段&主键&类型&是否为空&备注\\ }{ ID&是&Int&NOT NULL&特征向量维度序号\\ MethodName&否&Text&NOT NULL&函数名\\ }{\item } 构造特征向量时,先初始化一个全为0的特征向量,然后利用SQL查询语句确定代表某一函数名的维度序号:\\ select ID from Omega where MethodName = “待查函数名”;\\ 并将特征向量($\omega$)的第~ID~位设置为1。见式(\ref{omegai})。 \begin{equation}\label{omegai} \omega_i = \begin{cases} 1 & i = ID \\ 0 & else \end{cases} \end{equation} \subsection{特征库构建模块} 特征库构建模块实现于~PC~端,恶意样本来自各大权威机构公布的数据,详见第\pageref{omegai}页\ref{omegai}小节,其流程如图~\ref{flow5}~所示,特征库数据模型构建方法如下: \begin{pics}[htbp]{特征库构建流程}{flow5} \addsubpic{KNN特征库构建流程}{width=0.3\textwidth}{flow5-1} \addsubpic{K-L~变换矩阵构建流程}{width=0.3\textwidth}{flow5-2} \addsubpic{LDA~投影矩阵构建流程}{width=0.3\textwidth}{flow5-3} \end{pics} \begin{enumerate} \item 最近邻居(KNN)算法\par KNN~算法的特征库就是恶意程序样本的特征向量集合,我们将这些特征向量存储到数据库中。 \item 主成分分析(PCA)算法\par 考虑到文献\citeup{wangang1912}\citeup{zhaokaihua1995}中的适用条件,由于我们的特征向量维度远大于样本数量,所以需要去掉冗余数据,使训练数据矩阵为可逆矩阵才能使用线性判别分析(LDA)算法。 PCA~方法主要是通过对协方差矩阵进行本征分解,以得出数据的主成分(即本征矢量)与它们的权值(即本征值)。PCA~ 提供了一种降低数据维度的有效办法;如果分析者在原数据中除掉最小的本征值所对应的成分,那么所得的低维度数据必定是最优化的(也即这样降低维度必定是失去信息最少的方法)。 我们的目标是把高维的数据集~$\Omega_B$~和~$\Omega_M$~变换成具有较小维度的数据集~$Y_B$~和~$Y_M$。$Y_B$~和~$Y_M$~是矩阵~$\Omega_B$~和~$\Omega_M$~的~Karhunen–Loève~变换(K-L~变换)。即~$\mathbf{Y}=\mathbb{KLT}\{\mathbf{X}\}$。\\ 计算特征向量平均值见式(\ref{mean})。 \begin{equation}\label{mean} u=\dfrac{1}{N} \sum_{\omega \in \Omega_B \cup \Omega_M} \omega \end{equation} 从~$\Omega_B$~和~$\Omega_M$~中减去平均值~$u$~见式(\ref{Omega_u})。 \begin{equation}\label{Omega_u} \begin{split} B & =\begin{vmatrix}\Omega_B \\ \Omega_M \end{vmatrix}-hu\\ & \text{其中h是全为1的列向量。} \end{split} \end{equation} 求协方差矩阵~C~见式(\ref{getC})。 \begin{equation}\label{getC} C=B \cdot B^T \end{equation} 计算~C~的特征值和特征向量,提取不为0的特征值所对应的特征向量,构成~K-L~变换矩阵~W。\\ 所以,$Y_B$~和~$Y_M$~可由式(\ref{ybym})计算。 \begin{equation}\label{ybym} \begin{split} Y_B &= \Omega_B \cdot W \\ Y_M &= \Omega_M \cdot W \end{split} \end{equation} 最后我们将~K-L~变换矩阵~W~存储在数据库中。 \item Fisher~线性判别分析(LDA)\par \threelinetable[htbp]{ldaparameterdeftable}{\textwidth}{lXlX}{LDA算法变量定义} {变量&定义&变量&定义\\ }{ $S_b$ & 样本类间离散度矩阵 & $x$ & 一个程序\\ $S_i$ & 样本类内离散度矩阵&$X_M$ & 恶意程序集合\\ $S_w$ & 总类内离散度矩阵&$X_B$ & 非恶意程序集合\\ $W$ & 投影方向向量&$y_M$ & 恶意样本的投影值 \\ $J_F(W)$& Fisher~准则函数&$y_B$ & 非恶意样本的投影值\\ $M$ & 恶意(Malice)的缩写&$y_0$ & 识别阈值点\\ $B$ & 非恶意(Benign)的缩写&&\\ }{ \item } 应用统计方法解决模式识别问题时,一再碰到的问题之一是维数问题。在低维空间里解析上或计算上行得通的方法,在高维空间里往往行不通。因此,降低维数有时就成为处理实际问题的关键。在数学上总是可以把高维空间样本投影到一条直线上,形成一维空间,即把维数压缩到一维。但是投影方向有无数种,若把样本投影到一条任意的直线上,可能使几类样本混在一起无法区分,如图~\ref{fisher1}~所示。。但在一般情况下,总可以找到某个方向,使在这个方向的直线上,样本的投影能分开得最好,如图~\ref{fisher2}~所示。。 问题是如何根据实际情况找到这条最好的、最易于区分的投影线。这就是~Fisher~法所要解决的基本问题。\par \begin{pics}[htbp]{Fisher~线性判别基本原理}{fisher} \addsubpic{最优方向投影}{width=0.4\textwidth}{fisher1} \addsubpic{K-L~任意方向投影}{width=0.4\textwidth}{fisher2} \end{pics} 描述~LDA~算法前,首先定义几个基本变量,变量定义见表~\ref{ldaparameterdeftable}。LDA~算法步骤如下: \begin{enumerate} \item 计算样本均值向量~$m_i$: \begin{equation*} m_i=\dfrac{1}{N_i}\sum_{y \in Y_i}y ~~~~,i=B,M \end{equation*} \item 计算样本类内离散度矩阵~$S_i$~和总类内离散度矩阵~$S_w$: \begin{align} S_i & = \sum_{y \in Y_i}(y-m_i)(x-m_i)^T ~~~~,i=B,M\\ S_w & = P(x|x \in X_B)S_B + P(x|x\in X_M)S_M \end{align} \item 计算样本类间离散度矩阵~$S_b$: \begin{equation*} S_b=P(x|x \in X_B)P(x|x\in X_M)(m_B-m_M)(m_B-m_M)^T \end{equation*} $P(x|x \in X_B)$~和~$P(x|x\in X_M)$~是恶意程序和非恶意程序的先验概率,根据目前~Android~市场的情况,我们取~$P(x|x\in X_M)=0.001$。 \item Fisher准则函数为: \begin{equation} J_F(W) = \dfrac{W^T S_b W}{W^T S_w W} \end{equation} 为求函数取极大值时的~$W^*$。可用拉格朗日乘数法,定义拉格朗日函数为: \begin{equation*} \dfrac{L(W,\lambda)}{W} = S_bW-\lambda S_w W \end{equation*} 另偏导数为零,得 \begin{equation*} S_b W^* = \lambda S_w W^* \end{equation*} 其中~$W^*$~就是~$J_F(W)$~的极值解。因为~$S_w$~可逆,等式两边左乘~$S_w^{-1}$,可得 \begin{equation*} S_w^{-1} S_b W^* = \lambda W^* \end{equation*} 所以求~$W^*$~即求矩阵~$S_w^{-1} S_b$~的特征值问题。在我们这个特殊情况下,只有两种类别,故 \begin{equation*} S_b W^* = (m_B-m_M)(m_B-m_M)^T W^* \end{equation*} 其值为一标量,所以对~$W$~投影方向无影响。忽略这个标量的比例因子可得, \begin{equation*} W^* = S_w^{-1} (m_B-m_M) \end{equation*} \item 求出~$W^*$~后即可计算: \begin{align} y_M & = mean(W^*T \cdot Y_M) \\ y_B & = mean(W^*T \cdot Y_B) \\ y_0 & = \dfrac{m_B+m_M}{2} + \dfrac{\ln (P(x|x\in X_B)/P(x|x\in X_M))}{N_B+N_M-2} \end{align} 最后将LDA变换矩阵~$W$、$y_M$、$y_B$、$y_0$保存在数据库中。 \end{enumerate} \end{enumerate} \section{本章小结} 本章介绍了~AFace~系统的实现细节,它是一个由~Android~端和~PC~端两部分组成的系统。我们首先介绍了系统的设计原则。然后介绍了我们在此原则下设计的检测流程及其背后的检测原理。最后,作为一款完整的产品,还介绍了系统的产品软件架构以及产品的界面设计。