-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtipuesearch_content.js
More file actions
1 lines (1 loc) · 99.6 KB
/
tipuesearch_content.js
File metadata and controls
1 lines (1 loc) · 99.6 KB
1
var tipuesearch = {"pages":[{"title":"论文笔记集 DeepLearning for Web Attack Detection","text":"在zeroWall一文中, 已经简单介绍了利用机器学习辅助Waf的方法. 实际上zeroWall一文所述的领域即网络攻击检测(web attack dection). 这里简述一些阅读过的但整体方法不够有启发性或实验不够solid的论文. Anomaly-Based Web Attack Detection: A Deep Learning Approach 本文认为一组URL可以规范化为如下形式, 即abs_path表示资源地址, 而query总是跟在\"?\" 标记之后 \"http:\" \"//\" host [ \":\" port ] [ abs_path [ \"?\" query ]] 首先将一组URL经过序列化后分为两个部分: URL本身(图中表示为全部URL, 但按照文章所表述的URL Path 应该不含query部分)以及Query部分, 见图1. 随后将两组数据经过分词之后分别传入两个RNN结构(两层的GRU或LSTM)的神经网络以及计算其异常概率, 最后将所有的输出汇总(文中并未给出使用何种方式汇总两组RNN给出的多组异常概率)并输出给一MLP层作为最终的异常概率. 见图二 实验环节, 本文使用 HTTP CISC数据集 进行测试, 其结果如图三所示 结论 基于有监督的异常检测的泛化性是一个比较严重的问题, 而且本文因为工作量的较大原因仅处理了HTTP GET的请求, 在网络攻击中POST等其他提交数据的请求同样是十分危险的. 实验环节, 仅在一个较小的数据集上进行了处理,同时实验细节的讲述也比较含糊. 当然本文也提出了一些比较有意思的观点: 本文认为将一个URL请求视为时间序列, 字符的顺序位置都会对异常检测有所帮助, 比如\"id=1/ union /union/ select /select+1,2,3/*i\" 很明显是一个sql注入, 因为ID一般都接受一个数字符号. 但对于这一点作者并未详细论证, 直接使用了RNN对这一\"特征\"进行了统一建模. 如果对这一点进行深入研究, 将其作为辅助特征再次插入特征集合, 应该会有很好的效果 Web Application Firewall using Character-level Convolutional Neural Network 本文基于CLCNN(Character Level CNN)对异常的HTTP请求进行识别. 首先将原始的HTTP请求使用URL Decode, 随后将解码后的URL请求用0填充指1000bytes的长度/裁剪至1000. 随后利用词嵌入将其表示为128维的向量, 最后利用一维卷积和全连接输出其异常概率. 见图四 实验环节, 本文使用 HTTP CISC数据集 进行测试, 其结果如图五所示 结论 与上一篇文章相同基于有监督的机器学习对异常请求进行处理, 其主要问题也与上一篇问题类似. 相对而言这篇论文比较重要的一点是每条请求使用该模型处理只需要2.4ms. 处理速度对于Wad这一问题是很重要的, 但其他文章都很少提及这一点. A Deep Learning Method to Detect WebAttacks Using a Specially Designed CNN 本文与Web Application Firewall using Character-level Convolutional Neural Network一文类似, 都使用CLCNN网络结构处理HTTP Request. 但细节上本文, 将URL Request进行了分词处理, 随后将经过词嵌入的各个词向量进行卷积以及拼接, 最后交由MLP进行输出处理. 见图六 实验方面, 数据集仍然采用十分常见的CSIC 2010数据集, 按照7:0.5:2.5的比例划分数据集. 最后的Accuracy达到了百分之96.49 结论 本篇论文和上一篇论文基本一致, 区别为一个是Chararter Level 一个是World Level. Deep Anomaly Detection in Packet Payload 本文的主要目的是对网络数据包负载进行异常检测, 其核心观点是网络数据负载中的异常有两种模式long term 异常数据 以及 short term异常数据. 如下图七所示 针对这一特点, 作者设计了一种负载异常检测框架, 其由2部分组成: 一个用于提取特征的滑动窗口. 一个有LSTM + CNN + MLP的检测器. 框架结构如下图八所示 下面对流程结构中的一些关键点进行解释 Data Preprocessing: 实际就是将网络中的bit利用网络协议进行解析, 以便于准确的提取Payload段中的内容 BlockSequence Construction: 文中说使用滑动窗口, 实际上就是ngram. 作者将ngram提取出的结构, 分为高频率的字段, 和低频率的字段. 对于低频率的字段且不符合字典(特征库)的字段直接丢弃(文中详细描述并未提及, 仅在Introduction中提到filtrate by dictionary). 对于高频率字段也会经过字典选择. 实际上字典储存了数据集中所有字段的频率, 通过人工选择频率界限. Block Embedding: 即word embedding. 其基于 inear relational embedding 进行词嵌入. 模型方面: 基于LSTM(全输出模式) + CNN + MLP进行输出. 见下图九 实验方面: 本文在三个数据集上进行实验 CSIC 2010 , CIDIS 2017 以及 ISCX 2012 数据集. Conclusion 一篇基于有监督的异常检测, 辞藻华丽. 特征提取和模型方面比较传统. 比较有新意的地方在于, 采用全输出的LSTM结构作为二次特征提取器, 结合CNN三次提取特征. 但模型比较庞大, 估计处理时间会很长, 吞吐量难以保证. Locate-Then-Detect: Real-time Web Attack Detection via Attention-based Deep Neural Networks 本文设计了一种名为LTD(locate then detect)的基于Attention机制的系统来检测网络攻击, 同时也基于Detection机制来定位(解释)网络攻击的敏感区域. 该系统分为两个子模块, 用于定位可疑区域的PLN(payload locating network), 用于进行分类的PCN(payload classification network). 通过PLN的过滤, LTD减少了82.6%的计算成本, 使得对于每个请求仅需5ms处理时间. 整体结构见下图十 Method PLN: PLN作为第一阶段的神经网络, 与其他神经网络一样其输入需要经过特殊处理. PLN本质上就是个简易的Detection模型 词嵌入, 尽管作者将这一阶段称为网络请求嵌入, 但其本质上仍然为将长度为L的请求嵌入为L*X维度的向量 特征提取, 利用Xception模型提取特征, 即CNN提取特征 候选区域, 两个1*m(m = embedding size, 以保证语义完整性)的CNN, 一个用于回归(输出bounding box), 一个用于分类(输出类别). 于检测模型相同, PLN会输出p个Anchors. 并设置Anchor大小大于3, 范围在 [0, L]之间并且Anchor内的数据不含有太多的0(padding). 训练PLN和训练Detection模型基本一致, 如IoU小于0.2的bounding box作为负样本, 如 负样本与正正样本比例为3 : 1, 如PLN的训练公式为 $$ \\begin{aligned} L\\left(l_{i}, p o s_{i}, p_{i}, p o s_{i}^{*}\\right) & = \\frac{1}{N_{cls}} \\sum_{i} L_{c l s}\\left(l_{i}, p_{i}\\right) \\\\ &+ \\lambda \\frac{1}{N_{r e g}} \\sum_{i} l_{i} L_{r e g}\\left(p o s_{i}, pos_{i}^{*}\\right)\\\\ \\end{aligned} $$ 其中 \\(\\lambda\\) 为1 ,i表示训练集中第i个anchor, 当 \\(l_i\\) 为ground truth时为1, 否则为0. \\({pos}_i, {pos}_i^*\\) 分别表示ground truth和预测的值. \\(L_{cls}\\) 为log损失, \\(L_reg\\) 为平滑L1损失, 其公式如下 $$ {L_{1}}(x)=\\left\\{\\begin{array}{ll}0.5 x^{2} & \\text { if }|x|<1 \\\\ |x|-0.5 & \\text { otherwise }\\end{array}\\right. $$ PCN: 经过PLN确定可疑区域后, PCN将会对可以区域进行分类检测. PCN基于Text CNN结构: 5层CNN结构 + overtime max pooling. 其损失函数设计如下 $$ L_{P C N}=-\\frac{1}{N} \\sum_{i}^{N} \\sum_{j}^{K} y_{i j} \\log \\left(p_{i j}\\right)+\\lambda\\|\\mathbf{W}\\|, $$ 网络攻击标注: PLN模型的训练需要大量的标注数据, 作者使用 HMM-WEB 模型进行自动标注 Experiments 实验在CSIC数据集以及物理网络中提取的数据集. 并于传统Waf, libinjection 以及HMM-WEB进行了比较. 其结果如下图十一 Conclusion 本文开创性的将Object Deteciton 和 异常检测结合在一起. 但标题中提及的Attention based于比较熟知attention并不相同, 实际上是指这种先定位后检测的过程. 将系统的\"注意力\"集中到可以的区域上. 本文最大的问题应该在使用HMM-WEB提供标注上, 不确定会有多大的影响.","tags":"AIForSecurity","url":"/dl4wad.html","loc":"/dl4wad.html"},{"title":"论文笔记集 Statistical Learning for Web Attack Detection","text":"上一文种主要介绍一些基于深度学习的网络攻击检测论文, 这里则主要介绍一些基于传统机器学习(统计学习)的论文. An adaptive system for detecting malicious queries in web attacks 本文时一篇基于统计学习的网络攻击检测论文. 本文基于自适应学习策略以及利用SS(suspicion selection)和ES(exemplary selection)改进SVM算法来进行有监督的网络攻击检测任务. 本文的架构如下图一所示 Method 根据架构图, 本文的架构相对来说比较简单. 相对来说, 重点在于SS, ES以及对SVM的改进. 下面对一些术语以及方法进行解释 自适应学习: 文中定义自适应学习为可以通过适应新型攻击的行为来检测最新的未知攻击. 对SVM而言, 在以确定间隔的情况下, 出现在间隔内的样本如何进 行正确检测策略. SVMAL一文给出了一个方法. 即简单的将间隔内的样本分类归属为离其最近的分类平面. SVM Hybrid: 如图所示, SVM Hybrid通过结合SS以及ES实现自适应学习策略. 其公式定义于传统的SVM无异 $$ \\begin{aligned} &K(x, z) = \\varphi(x)^\\varphi(z)\\\\ &max_\\alpha \\sum^n_{i = 1}\\alpha_i - \\frac{1}{2}\\sum^n_{i, j = 1}\\alpha_i\\alpha_j y_i y_j x_i^T x_j,\\\\ &st \\space 0 \\leq \\alpha_i \\leq C \\space (i = 1, ..., n), \\sum^n_{i = 1}\\alpha_i\\alpha_j = 0 \\end{aligned} $$ suspicion selection(SS): SS的方式为利用聚类算法寻找潜在的信息分类(informative queries). 其具体方法如下 模型训练完成的情况下, 落入的间隔内的数据被称为Q. Q将会根据其核距离来排序 $$ f(x) = \\sum^n_{i=1} \\alpha_i y_iK(x_i, x) + b $$ 将最小的核距离定义为模糊空间的下边界. \\(f_{lower} = \\displaystyle\\min_{x\\in Q}\\) . 将最大的核距离定义为模糊边界的上边界. \\(f_{upper} = \\displaystyle\\max_{x\\in Q}\\) . 聚类算法使用K-medoids. 将K-medoids的中心定义为suspicion, 即最容易误分类的样本. K-medoids公式亦与传统公式无异 $$ \\begin{aligned} &E = \\displaystyle\\sum^k_{j = 1}\\sum_{x \\in C_j}|\\varphi(x) - \\varphi(M_j)|\\\\ &|\\varphi(x) - \\varphi(M_j)| = \\sqrt{K(x, x) + K(M_j, M_j) - 2k(x, M_j)} \\end{aligned} $$ exemplary selection(ES): ES用于表达典型的恶意样本. 虽然SS对样本可以进行分类, 但其误检率较高, 利用ES来进一步确认其分类. ES基于kernel farthest first(KFF)这一贪婪启发算法来确定典型样本. 令未达标的数据未U, 达标过的数据未L. 最远距离定义为L中的数据y到U中的一个数据x的距离之和的最大值. 公式如下 $$ \\displaystyle\\argmax_{x \\in U}(\\sum_{x \\in L} |\\varphi(x) - \\varphi(y)|) $$ 数据预处理: 提取Get请求 数据清洗: 仅保留response在200-300字节的的请求 数据标准化: 将ascii, unescaping字符转换为小写, 并删除长度小于4的请求 按照RFC2616过滤不安全的字符 利用2Gram对数据再次分割. 特征压缩: 卡方校验, 信息增益(info gain, 选择头800), DF(document Frequency), top selection(首选, 选择150, 200, 300, 500, 800, 1100, 1500 and 2000), PCA(principal component analysis, 主成分分析法, 选择top 80), RP(random Projection, 随机投影)以及reservation quantities(选择10, 20, 30, 40, 60, 80, 150 and 300) Experimental 实验在32GRam以及Intel 2.93GhzCpu上进行, 使用Weka和Libsvm实现baseline以及Meta Svm. 数据为内部数据并未开源. MetaSvm使用RBF核, 参数为 \\((C,\\gamma) = (0.05, 2)\\) , 基于网格搜索的交叉验证来进行验证. 对自适应功能验证的结果如下(主要与SvmAL对比) ; 与传统框架对比, 数据基于CSIC2010, 结果如下 ; Conclusion 本片文中创新型的提出了SS以及ES机制来辅助SVM, 解决其对新样本的识别能力. 在深度学习大行其道的今天, 基于统计学习的模型比较少见, 且效果也相对平庸 但作者提出的SS以及ES机制对在线学习也许有一定帮助. Anomalous Payload-based Network Intrusion Detection 为了构建一个自动化的, 通用的, 增量更新的, 高准确率的, 放模仿攻击的, 高吞吐的异常检测系统. 本文提出了一种基于language Independent(语言独立的)的统计模型并结合Ngram特征提取算法的入侵检测模型. 模型十分简单甚至没有用到复杂的统计模型或神经网络, 其主要用一系列的统计特征提取算法构成. 下面对细节进行说明: Method 基于长度条件的Ngram 负载模型(Length conditioned ngram payload model) 利用 1gram算法将payload进行拆分, 随后统计各个字符出现的频率, 最后计算其均值以及标准差. 标题中的长度条件是指对不同长度的报文进行分别计算. 训练阶段更具这一方法可以构建出 \\(M_i, j\\) 个payload模型. 在验证阶段, 同理计算出该报文的频率, 均值以及方差在于 \\(M_i, j\\) 进行对比. 简化马氏距离(simplified Mahalanobis distance) 对比 \\(M_i, j\\) 于新报文阶段便采用马氏距离进行计算, 计算结果越高新报文异常的概率则越大 $$ d^2(x, \\bar{y}) = (x - \\bar{y})^T C^{-1}(x - \\bar{y}) $$ 其中 \\(x\\) 是新请求, \\(\\bar{y}\\) 是平均后的训练集模型. \\(C^{-1}\\) 为协方差矩阵的逆,即 \\(C_{i, j} = Cov(y_i, y_j)\\) 其中 \\(y_i, y_j\\) 是训练集中的第i/j个向量. 为了加速计算, 简化的马氏距离算法为 $$ d(x, \\bar{y}) = \\sum^{n-1}_{i=0}(|x_i - \\bar{y_i}|/(\\bar{\\sigma_i})+ \\alpha) $$ 其中n为出现字符的总数. \\(\\sigma\\) 为标准差, \\(\\alpha\\) 为平滑系数. \\(\\alpha\\) 越高, 样本的置信度越低, 但更能表现真实的数据分布 增量学习 本文结合增量学习来处理新的数据样本, 同时对于过时的数据, 本文也提出了一种衰减参数来控制过时的数据. 对于一字符的平均频率 \\(\\bar{x} = \\sum^N_{i = 1}x_i/N\\) , 对于已经存储的均值, 通过一下方法进行更新 \\(\\bar{x} = \\frac{\\bar{x}\\times N + x_{N + 1}}{N + 1} = \\bar{x} + \\frac{x_{N + 1} - \\bar{x}}{N + 1}\\) 由于标准差是方差的平方根, 又可以将方差利用期望进行改写, 即 \\(Var(X) = E(X - EX)^2 = E(X)^2 - (EX)^2\\) . 利用聚类减少模型尺寸 模型可能存在两个问题, 一是总体模型过大, 类似的模型过多. 二是针对部分个体模型其较稀疏. 为了解决这些问题本文使用简化的马氏距离计算模型之间的相似度. 对于稀疏的模型, 则从相似的模型中\"借\"数据, 或者提高平滑系数. 对于不稀疏的模型, 则定义一个threshold t 来决定是否进行模型合并. 无监督学习 基于马氏距离的检测方法, 同样可以用于无监督学习. 因为异常的样本在网络中比较少, 那么对整体的影响也相对较少. 并且在训练集中, 若存在异常样本, 这些样本也会如同异常点(outliers)一般用于被辨别出来. Z-String ZString是指将字符序按照其频率再次排列. 作者认为这个特征可以有效地检测蠕虫. 即拥有相似ZString特征的网址, 受到蠕虫攻击的概率是相同的. Zstring的效果如下图五所示: 实验阶段: 本文使用 DARPA1999 IDS 数据集进行实验, 实验效果如下图六所示: Conclusion 尽管本文完成时间比较早, 并且其检测效果也相对较差. 但本文使用无学习的策略, 进行检测对无网络攻击这一高吞吐需求的任务中是很有意义的. 利用传统的无学习的策略做无监督学习, 利用深度学习进行特征提取或许是一个一个解决方法. HMMPayl: an Intrusion Detection System based onHidden Markov Models 本文设计了一种名为HMMPayl的基于隐马尔可夫模型的入侵检测系统. 如下图七所示 Method 该模型分为三个阶段: 1. 特征提取. HMM模型处理序列数据具有先天优势 , 但随着序列长度的提升 , 由于前后向算法的缘故导致序列内计算相关性程度会下降 ( 从实验效果触发 , 即越长的序列越容易分类为威胁 ). 其次当各个序列长度类似时 , 其效果最好 . 故为解决上述问题 , 特征提取算法设计为$ N = L - n + 1 $ , 其中 L为负载长度 , n为滑动窗口大小 . 简单来讲就是使用 Ngram . 实验中作者设置 N = 5 使用 Ngram对长序列切片后 , 会产生许多冗余数据 , 故还需要对数据进行序列抽样 ( sequence sampling ). 因为第 t个序列的最后n - 1 个 bytes是t + 1 序列的 n - 1 个 bytes的开头 . 作者假设并并通过实验得到在 10 个序列内的数据都是类似的 . 见下图八 . 故作者从这 10 个序列中随机抽样 , 作为一长段序列的特征传递给下一阶段 . 并且作者认为这种随机抽样的方法对欺骗攻击十分有效 . ! [ 图八 ]( https : // d3i71xaburhd42 . cloudfront . net / 480205 cdc0b039764478a27b8accdcabe1e1e108 / 16 - Figure7 - 1 . png ) 模式分析. 模式分析即HMM模型的过程, 对于每个payload P HMM计算O(Ngram输出的集合)中的每个序列出现的概率即: $$ p_{j}=P\\left(o_{j} \\mid \\lambda\\right), j=1, \\ldots, N $$ HMM的原理以及过程这里不再赘述. 最后综合整体的概率公式为 $$ P(O \\mid \\lambda)=\\frac{1}{N} \\sum_{j=1}^{N} p_{j}=\\frac{1}{N} \\sum_{j=1}^{N} P\\left(o_{j} \\mid \\lambda\\right) $$ 分类阶段 本文使用Baum-Welch算法去计算HMM中的参数(即进行推理). 并且本文出于统计原因(降低误检率), 计算原因(逃离局部最优解)以及表示原因(单一的分类器无法准确的表达分类平面)采用了多分类系统结构进行分类. 结构上如图七所示. 多分类系统有两种综合结果输出的方式: 分类器混合(按照最大概率, 最小概率, 平均或几何平均)以及分类器选择(理想成绩选择器, ideal Score Selector, 公式如下) $$ p_{j}=P\\left(o_{j} \\mid \\lambda\\right), j=1, \\ldots, Ns_{i}^{*}=\\left\\{\\begin{array}{ll} \\max \\left\\{s_{i j}\\right\\} & \\text { 当 } x_{i} \\text { 为正常数据 } \\\\ \\min \\left\\{s_{i j}\\right\\} & \\text { 当 } x_{i} \\text { 为威胁数据 } \\end{array}\\right. $$ 实验中使用分类器混合方式进行结果综合输出. Conclusion 本文的实验十分的详实, 对于每一个参数的选择都进行了大量的实验以确定最优的解. 同时也对每一个报文的成立时间进行了计算. 0.02ms一个请求. 个人认为本文在数据处理这一节的探讨十分有意义, 因为通常Ngram设置为2, 3这些小数, 但对网络数据负载大的N会更能体现区段之间的关联性. 本文通过实验表明了N=5 - 10 对于网络负载是一个合适的值.","tags":"AIForSecurity","url":"/sl4wad.html","loc":"/sl4wad.html"},{"title":"协议分析与还原 RTMP协议","text":"introduction RTMP协议全称为Adobe's Real Time Message Protocol(实时消息协议). 是一个建立在可靠网络链接上的双向消息多路复用的数据传输协议. 其设计用于传输视频, 音频以及数据消息 Definitions 这里对协议中一些特有的术语进行说明: - Message stream ID: 每一条消息都有一个独立的ID, 用于标记其自身. - Chunk: 一条消息的数据分片. 每条消息都会被拆分成为小的片段并在网络中发送. 每个Chunk保证其按照时间顺序, 端到端的进行发生以及重组. - Chunk Stream: Chunk在网络通信中的逻辑通道. - Chunk stream ID: 每片Chunk的ID, 用于标记其自身属于那条Message. - AMF(Action message Format): 一种用于序列化ActionScript(其Flash产品开发的一种基于ECMAScript的面向对象编程语言, 但现在Flash已被废弃, 并且现在RTMP协议也多用来单纯传输音视频文件, 不再传输FLASH的SWF文件)的Object Graph的二进制兼容格式, 其拥有2中版本, AMF0以及AMF3. Overview 上图为RTMP协议的概览, 其上半部分被称为Chunk Stream(包括TimeStamp部分), 下半部分则为Message. Chunk Stream Chunk Stream 在术语说明中容易被认为其是消息的分片, 但实际上Chunk Stream 还除了包括消息分片外, 还可以作为一条\"消息\"独立使用(控制报文, 握手报文, 这些报文本身并不含有Message). Handshake 一个RTMP协议开始于握手(握手就是典型的不含有Message的报文), 其分为三个阶段C0/S0, C1/S1, C2/S2. 其中C表示客户端, S表示服务, 每个阶段的客户端和服务端的握手报文结构相同. RTMP握手流程如下 每个阶段的报文结构如下C0/S0 这里的一个字节的数据用于标记本次通讯所使用的版本号, 目前有0, 1, 2, 3 四个版本, 但目前仅3为有效版本. C1和S1数据包长度固定为1536字节 其长度也固定为1536字节, 其中Time为C1/S1中的时间. 随机数回应(Random Echo)这一字段包含接收到C1/S1阶段的随机数. Chunking 握手完成后,网络链接会复用一个或多个分块流,每个分块流承载来自同一个消息流的一类消息。每一个Chunk的格式如下图所示: Basic Header: 1-3个字节, 该长度取决于Chunk Stream ID. Chunk Stream ID是一个变长的字段. 其有三种结构, 如下图所示. 当2-7bit数据为0, Basic Header长度为2字节, 2-7bit数据为1时Basic Header长度为3字节. 其余情况Basic Header长度为1字节. csid取值范围2-63 csid取值范围64-319 csid范围64-63399 注:这里的csid-64, 意为这8/16个字节的二进制数在加上64为真实的csid. 例如 ID为365时, 2-7bit为1, 余下的16bit为301. Message Header: 11/7/3/0个字节, 该长度取决于Basic Header中指定的fmt字段. fmt有4种取值0, 1, 2, 3. 当fmt为0, Message Header结构如下图 0号类型的header占11个字节, 必须用于一个块流的开头以及时间戳后退的情况 1号类型的header占7个字节, 用于开头块流的后续消息(变长的消息载荷, 如视频) 2号类型的header占3个字节, 用于开头块流的后续消息(定长的消息载荷, 如部分音频或数据格式) 对于3号类型的header, 其占0个字节即没有Message Header, 用于装载后续的分片. Extended Timestamp: 3个字节, 但是一个可选的字段 当Timestamp delta大于0xFFFFFF时, 该字段就会出现, 用来共同表示32位的时间戳. Chuck Data: 有效载荷 Message Stream 一条报文可以被分为Chunk Stream部分和Message Stream部分, 上一节中描述了Chunk Stream部分的字段. 本节讲解Message Stream部分的字段. Message Stream部分的格式如下图. 注: 下图的字段布局并不是真实的字段布局, 并且出现的Payload Length和TimeStamp字段是公共字段同时属于Chunk Message和Stream Message. 准确的字段布局见Overview中的图像. Message Type Message Type 有Chunk header中的Message Type ID字段确定. 当Message Type ID为1, 2, 3, 5, 6时, 其代表的都为控制消息. |Message Type ID|效用| |--|--| |1|用来控制最大块的大小, 大小为32bit, 第0位恒定位0. 默认情况下Chunck的大小为128字节, 该报文可以将Chunk的大小设置为1-1677215(1 - 0xFFFFFFF). 但改控制消息的取值为31位二进制数.| |2|用来终止消息, 大小为32bit, 内容为要终止的Chunk Stream ID. | |3|用来确认消息, 大小为32bit, 内容为当前时间接受到的字节数总数.| |5|用来确认Windows大小, 大小为32bit, 内容为windows的大小. 接收端在接收到windows大小后必须发送确认消息(Message Type ID为3)| |6|用来设置对等带宽, 大小为40bit, 内容为32bit的windows大小和8bit的限制类型. 接收端收到消息后,通过将已发送但尚未被确认的数据总数限制为该消息指定的windows大小,来实现限制输出带宽的目的。 限制消息有3中类型, 0 - hard: 接受端的输出带宽限制为windows大小.1 - soft: 接收端的输出带宽限制为接收到的和当前的windows中较小的一方. 2 - Dynamic: 若上一条为Hard, 则本条也为hard. 否则本条无效.| 当Message Type ID为4时作为用户控制消息. 该消息携带事件类型和事件数据两部分. 其格式如下图 其支持7种事件: 事件类型 & Event Type 描述 流开始 = 0 服务端发送该事件, 用来通知客户端一个流已经可以用来通讯了. 默认情况下, 该事件是在收到客户端连接指令并成功处理后发送的第一个事件. 事件的数据使用4个字节来表示可用的流的ID 流结束 = 1 服务端发送该事件, 用来通知客户端其在流中请求的回放数据已经结束了. 如果没有额外的指令, 将不会再发送任何数据, 而客户端会丢弃之后从该流接收到的消息. 事件数据使用4个字节来表示回放完成的流的ID 流枯竭 = 2 服务端发送该事件, 用来通知客户端流中已经没有更多的数据了. 如果服务端在一定时间后没有探测到更多数据, 它就可以通知所有订阅该流的客户端, 流已经枯竭. 事件数据用4个字节来表示枯竭的流的ID 设置缓冲区大小 = 3 客户端发送该事件, 用来告知服务端用来缓存流中数据的缓冲区大小(单位毫秒). 该事件在服务端开始处理流数据之前发送. 事件数据中, 前4个字节用来表示流ID, 之后的4个字节用来表示缓冲区大小(单位毫秒). 流已录制 = 4 服务端发送该事件, 用来通知客户端指定流是一个录制流. 事件数据用4个字节表示录制流的ID ping请求 = 6 服务端发送该事件, 用来探测客户端是否处于可达状态. 事件数据是一个4字节的时间戳, 表示服务端分发该事件时的服务器本地时间. 客户端收到后用ping响应回复服务端 ping响应 = 7 客户端用该事件回复服务端的ping请求, 事件数据为收到的ping请求中携带的4字节的时间戳. 当Message Type ID为15/18时作为数据消息. 15表示AMF3编码, 18表示AMF0编码. 通过该消息发送元数据和其他用户数据元数据包括数据(音频、视频)的创建时间、时长、主题等详细信息 当Message Type ID为16/19时作为共享对象消息. 16表示AMF3编码, 19表示AMF0编码. 注: 共享对象是一个在多个客户端、示例之间进行同步的Flash对象(键值对集合). Flash已经废弃这里不再描述 当Message Type ID为20/17时作为指令消息. 17表示AMF3编码, 20表示AMF0编码. 发送这些消息来完成连接、创建流、发布、播放、暂停等操作 当Message Type ID为22作为组合消. 其格式如下 当Message Type ID为8, 表示音频消息 当Message Type ID为9, 表示视频消息 Message Payload Message Payload本身并不是RTMP协议标准种的内容, 但作为还原的一部分. 这里额外写入. Message Payload Control Control字段占1个字节, 其由2个4bit数据组成. 前4bit表示是哪一类型的数据, 后4bit表示其控制消息. Audio 前4bit 中2bit 中1bit 后1bit 音频格式 采样率 音频大小 音频类型 0 = Linear PCM, 大顶端 0 =5.5Khz 0 = snd8bit 0 = sndMono 1 = ADPCM 1 = 11Khz 1 = snd16bit 1 = sndStereo 2 = MP3 2 = 22Khz 2 = snd16bit 3 = Linear PCM, 小顶端 3 = 44Khz 4 = Nellymoser 16khz mono 5 = Nellymoser 8khz mono 6 = Nellymoser 7 = G.711 A-law logarithmic PCM 8 = G.711 mu-law logarithmic PCM 9 = Reserved 10 = AAC 11 = Speex 14 = MP3 8Khz 15 = Device-Specific sound Video 前4bit 后4bit 帧类型 编码ID 1 = 关键帧, AVC 1 = JPEG 2 = 内部帧, AVC 2 = H263 3 = 一次性的内部帧, 仅H263 3 = ScreenVideo 4 = 生产的关键帧, 仅服务端可用 4 = On2 VP6 5 = 视频信息 控制帧 5 = 带Alpha通道的On2 VP6 6 = Screen Video 2 7 = AVC(H264) 结语 本文档主要用于协议还原, RTMP协议的详细过程并未准确描述. Payload中的Control 类型亦为描述完整. 若有兴趣看完全部文档请参见 RTMP官方文档 以及 FLV官方文档 . FLV文档中细致描述了Payload Control的类型.","tags":"Protocol","url":"/rtmp.html","loc":"/rtmp.html"},{"title":"论文笔记 ZeroWall: Detecting Zero-Day Web Attacks through Encoder-Decoder Recurrent Neural Networks","text":"Introduction Waf(web application firewall)一般通过规则过滤/触发的异常的Web请求. 通过安全研究员对已知攻击特征的提取来构成并拓展特征库. 但基于特征的Waf难以对0Day漏洞进行检测. 故本文提出了一种Encoder-Decoder RNN架构的无监督学习方案对0Day漏洞进行检测. 本文的核心思想在与将0Day的检测问题转换为翻译质量评定的问题. 简单的来讲即通过训练一个翻译器来将正常web请求A再次翻译为A'. 而当异常的web请求B翻译为B'时, 由于神经网络对B的特征拟合较差故B'的翻译质量也会较差. 以此来判定B是一个异常的web请求 Method 对于Waf吞吐量的是十分重要的, 完全基于AI检测的waf器吞吐量是一个重大缺陷, 故本文采用waf旁路架构, 基于已有的waf框架过滤异常请求. 神经网络本身不进行过滤处理, 仅用于检测0Day漏洞, 并结合安全人员将已发现的漏洞编写成规则添加进规则库. 下图为系统的架构图 可以看出整个系统架构分为两个部分(实际是三个部分, 即传统的waf框架自身的运行在图中被省略, 当流量未触发waf规则时, 其会被放行). 在offline periodic retrain部分中, 其分为四个阶段数据积累, 词汇表构建(vocabulary), 词汇解析(token parser)以及训练. 其主要功能就是词汇表构建和训练. 以保证能对新出现的请求进行正常识别. 在online detection部分中, 其分为六个阶段请求过滤(在图中未体现), 词汇解析, 翻译, 异常检测以及人工调查. 一条请求经过上述六个阶段后, 被安全人员确认为异常请求后将其改写为waf规则并添加至规则库中. 下面对一些细节进行描述 词汇解析: 词汇解析主要分3个模块, 词汇表构建(分词), 词汇序列化以及词嵌入 词汇表构建(分词): 将每一条请求根据空格以及标点进行切分, 随后将无用的词汇(变量)和一些无意义的词汇(&, = 这些在语句中大量出现的词)替换为占位符(placeholder). 最后将出现频率过高以及过低的词汇删除来构成词汇表 序列化: 仅保留出现在词汇表中的词, 以及替换变量为占位符 词嵌入: 使用word2vec进行词表示 翻译器: 翻译器基于Encoder - Decoder架构. Encoder: 基于LSTM模型, 将输入的请求经过分词, 序列化以及词嵌入后作为输入输入值LSTM模型 Decoder: 基于LSTM模型, Encoder接受到终止词后, 将其生成的预测和权重交付给Decoder, Decoder根据输入每一步生成预测结果. 异常检测: 前面提到本文将异常检测的问题转化为翻译质量测评问题, 在翻译质量评测中通常使用BLEU指标. 本文简单的将1 - BLEU 作为异常的可能性 白名单: 即使神经网络不再作为直接的过滤器, 但巨大的网络吞吐量对神经网络仍然无法处理, 故本文将已经处理过的请求Hash处理后保存下来, 以此进行过滤. Experiments 数据: 持续收集了8天的企业的网络流量 训练集与测试集: 将8天的流量两两分为7分, 头一天的作为训练集, 余下的作为测试集 Ground Truth与测试指标: Ground Truth由安全工程师进行验证, 测试指标为Precision, Recall以及F1. 见图二 可能性址标: 实验中使用CDF(Cumulative Distribution Function, 累积分布函数)对GLUE, BLUE, NIST, CHRF进行测试, 实验显示BLUE的效果最佳. 见图三 设备 CPU: Intel(R) Xeon(R) Gold 6148 CPU2.40GHz ∗ 2 RAM: 512GB RAM Conclusion 本文贡献在于将异常检测问题转换为机器翻译质量评测问题, 以及白名单机制减少无效推理过程(感觉这一步依然可以进行优化). 但也存在一些问题1. 无法防御数据投毒, 虽然文中作者解释waf会对这个进行处理, 但实际上waf不会对新类型数据进行过滤. 2. 相对来说数据量较少. 3. 文中没有提到对潜在的0day进行过滤, 虽然文中提出在大量正常样本的情况下, 少量的异常样本影响不大. 但正如前段时间爆出的qq邮箱会将某特定字段翻译为一段地址一样. 很难确定这一点没有影响. 很可能会导致一些漏报.","tags":"AIForSecurity","url":"/zerowall.html","loc":"/zerowall.html"},{"title":"数字图像取证 - 基于统计的取证 4","text":"引言 现在软件可以渲染一个非常写实的图像,从而分区CG还是相片已经是一个困难的问题。但是CG图像一般都渲染在一个理想的模型下(光照,几何形状甚至是), 那么统计量上CG一定与真实的图像存在差异. 下面将介绍一种方法: 利用小波变换得到的其高频以及低频分量进行统计学分析. 正交镜像滤波器 众所周知利用空间位置(spatial position), 方向(orientation)以及尺度(scale)等基本函数(如 小波变换)对图像进行分解后, 可以有效地完成图像压缩, 图像编码, 图像去噪抑或是材质合成等操作. 其主要是由于图像分解暴露出了有效用的统计特征. 下面介绍一种与小波变换紧密相关的滤波器- 正交镜像滤波器 , 其主要结构见下图 当其作用在一张RGB图像时, 镜像正交编码器会对每一个通道(R, G, B)提取其竖直子带 \\(V^c_i(x, y), 水平子带\\) H^c_i(x, y) \\(以及对角子带(subbands)\\) D^c_i(x, y)的特征. 其中 \\(c\\in{r, g, b}\\) . 更进一步的每子带的系数分布由每个子带的方向, 尺度以及色彩通道的均值, 方差, 偏度以及峰度来描述. 求解跨域高阶相关性信息 仅靠这正交镜像滤波器所获取到的统计量无法完全获取跨域的高阶相关性. 举个例子, 具有一种边缘在固定方向,多个尺度上延申的显著特征的图像. 这样的图像特征将会在多个尺度, 方向以及空间位置上具有显著的能量分布. 故在横向子带上的一个巨大的系数表明其空间中的左右邻居也会有巨大值. 简单来说, 即如果尺度i的系数很大, 那么尺度i+1的系数同样也会很大. 为了获取跨域高阶相关性, 这里就需要引入统计学习相关算法. 为便于描述仅考虑绿色通道上的垂直子带 \\(V^g_i(x, y)\\) . 一线性预测器在所有可能的空间, 方向, 尺度以及邻居色彩定于如下: $$ \\begin{aligned} |V^g_i(x, y)| &= \\omega_1|V^g_i(x - 1, y)| + \\omega_2|V^g_i(x + 1, y)| \\\\ &+ \\omega_3|V^g_i(x, y - 1)| + \\omega_4|V^g_i(x, y + 1)| \\\\ &+ \\omega_5|V^g_{i + 1}(x/2, y/2)| + \\omega_6|V^g_i(x, y)| \\\\ &+ \\omega_7|V^g_{i + }(x/2, y/2)| + \\omega_8|V^r_i(x, y)| \\\\ &+ \\omega_9|V^r_i(x, y)|\\\\ \\end{aligned} $$ 其中 \\(|\\cdot|\\) 为绝对值函数, \\(\\omega_k\\) 为标量权重. 上述的线性关系可以被简单的表示为矩阵相乘的形式 \\(v = Q\\Omega\\) . 权重 \\(\\omega\\) 可以利用最小二乘法进行求解 $$ \\Omega = (Q^TQ)^{-1}Q^Tv $$ 一般 \\(Q\\) 采用 \\(9 * 9\\) 的矩阵进行运算. 这样可以保证 \\(Q^TQ\\) 是可逆的. 最后在利用对数损失计算真实值与预测值之间的误差 $$ p = log(v) - log(|Q\\Omega|) $$ 同理对于纵向子带, 对角子带及其不同的色彩通道处理方法类似 实验结果 分类器使用二分类的LDA, 以及SVM进行检测 数据集则由40000张图像数据, 6000张CG图像组成, 为解决不同图像大小不一的情况, 仅提取图像中心256 * 256的像素. 按照上面的方法提取特征. 最后按照8:2的比例分割数据集. 使用LDA模型, 测试集上分类准确率为54.6%的照片准确率, 99.2的CG图像. 使用SVM模型, 测试集上分类准确率为66.8%的照片准确率, 98.8%的CG图像.","tags":"Digital Image Forensics","url":"/forensics_4_1.html","loc":"/forensics_4_1.html"},{"title":"数字图像取证 - 基于像素的取证 3","text":"缩略图 在JPEG文件格式中, 会在头部嵌入经过滤波,对比度调整,压缩的缩略图.这 些特定的操作就导致了不同的相机厂商或软件厂商的细微差异。 设一个原图为 \\(f(x, y)\\) ,那么一个图像经过下面6步骤进行制作 裁剪/填充 预滤波 降采样 对比度 亮度调整 JEPG压缩 裁剪/填充 当缩略图与原图的分辨率比例不相同时, 需要对图像进行裁剪/填充处理. 这一阶段会产生四个参数 \\(c_l, c_r, c_t, c_b\\) 分别表示左右上下的裁剪/填充系数 抽象预滤波, 降采样, 对比度以及亮度调整 完成裁剪/填充操作后, 后续的四个操作可以将其抽象为一组模型 $$ t(x, y) = \\alpha(D\\{\\hat{f}(x, y) * h_1(x, y)\\} * h_2(x, y)) + \\beta $$ 其中 \\(t(x, y)\\) 是缩略图, \\(D\\) 表示降采样操作, \\(h_1\\) 为预滤波, \\(h_2\\) 为后滤波(可选, 一般用于锐化处理), \\(*\\) 为卷积, \\(\\alpha, \\beta\\) 则是对比度系数以及亮度系数.为了简化模型, 做出如下假设 预滤波器为圆对称高斯模型, \\(exp(-(x^2 + y^2)/\\theta^2), 其中\\) \\theta$为宽度. 预滤波器是单元和. 后滤波器的大小为3x3. 后滤波器是对称的, 即 \\((h_2(x, y) = h_2(-x, y),h_2(x, y) = h_2(x, -y))\\) . 产生如下形式的滤波器(a b a; b c b; a b a) 后滤波器也是单元和, 约束$c = 1 - (4a + 4b) 在以上的约束下, 缩略图模型将会产生11个参数, 2个缩略图尺寸参数, 4个填充/裁剪参数, 1个预滤波参数 \\(\\theta\\) , 2个后滤波参数 \\(a, b\\) 以及对比度参数 \\(\\alpha\\) 和亮度参数 \\(\\beta\\) . 考虑到JPEG图像格式的特有参数128个, 即2个8x8的对亮度以及色彩通道的量化表. 故对于一个Jpeg文件总共可以产生139个参数对其进行描述. 求解剪切/填充参数 缩略图处理流程中剪切/填充的边界正相关于全尺寸图像的分辨率(已知), 但具体的比例仍然需要估算. 首先设定一个初始的符合分辨率比例关系的初始缩略图 \\(\\hat{f}_0(x, y)\\) . 故初始缩率图可以被建模为 $$ \\hat{t}_0(x, y) = D\\{\\hat{f}(x, y)\\} $$ 其中 \\(\\hat{f}_0(x, y)\\) 为原始图像, D为降采样操作, 其比例为 \\(max(N_x/n_x, N_y/n_y)\\) , \\((N_x, N_y)\\) 以及 \\((n_x, n_y)\\) 为图像和缩略图的尺寸. 随后初始缩率图经过各项异性(各个维度变换系数不相同)的缩放(scaling)和变换(translation)得到提取出的缩略图 \\(t(x, y)\\) $$ t(x, y) = \\hat{t}(s_xx + \\delta_x, s_yy + \\delta_y) $$ 其中 \\((s_xx, s_yy), (\\delta_x, \\delta_y)\\) 分别为缩放和变换系数. 在灰度图上基于粗粒度至细粒度的差分匹配算法(coarse-to-fine differential registration)求解上述参数 求解滤波器以及对比度和亮度参数 求解各滤波器以及对比度和亮度参数, 可以通过减少真实图像与预估图像之间的误差进行求解. 即 $$ E_1(h_1, h_2) = \\sum_{x, y}[t(x, y) - \\alpha(D\\{\\hat{f}(x, y) * h_1(x, y)\\} * h_2(x, y)) - \\beta]^2 $$ 但上述公式仅根据预滤波和后滤波得出, 无法求解对比度以及亮度. 故对于亮度与对比度系数, 给定滤波器的参数, 定义误差函数为 $$ E_2(\\alpha, \\beta) = \\sum_{x, y}[t(x, y) - \\alpha(D\\{\\hat{t}_h(x, y) + \\beta)]^2 $$ 其中 \\(\\hat{t}_h(x, y) = D\\{\\hat{f}(x, y) * h_1(x, y)\\} * h_2(x, y))\\) 利用最小二乘法即可 \\(E_2\\) 进行求解. 对于 \\(E_1\\) 则需要使用暴力搜索求解最小值, 或使用Nelder-Mead 最小化算法加速求解过程. 在实验中, 作者发现求解 \\(E_1\\) 时在傅里叶域中效果会更好, 即最小化 $$ E_1(h_1, h_2) = \\sum_{\\omega_x, \\omega_y}[||T(\\omega_x, \\omega_y)|| - ||\\hat{T}(\\omega_x, \\omega_y)||]^2 $$ 其中 \\(T(\\cdot)\\) 表示傅里叶变换后的真实缩率图 \\(t(\\cdot)\\) , \\(\\hat{T}(\\cdot)\\) 表示傅里叶变换后的预估缩率图 \\(D\\{\\hat{f}(x, y) * h_1(x, y)\\} * h_2(x, y))\\) , \\(||\\cdot||\\) 表示傅里叶变换的量级. 由于经过 \\( t(x, y) = \\hat{t}(s_xx + \\delta_x, s_yy + \\delta_y)\\) 的初始校准, 低频特征时十分均衡的, 故该损失函数在高频特征上进行计算 最后是, 128个量化表系数可以直接从量化表中获取. 参考文档 1.E. Kee and H. Farid. Digital image authentication from thumbnails. In SPIE Symposium on Electronic Imaging, San Jose, CA, 2010.","tags":"Digital Image Forensics","url":"/forensics_3_3.html","loc":"/forensics_3_3.html"},{"title":"数字图像取证 - 基于像素的取证 2","text":"前面介绍的均为一些跨图像的修改, 通过由于不同图像的不同的属性我们将图像修改/取证. 那么对于同一图像内的直接复制策略如何进行检测. 这里介绍基于SIFT特征与Ransac算法检测图像内复制粘贴. (这里有一个猜想, 一般图像复制粘贴的同时会对图像进行缩放裁剪, 结合上一节中重采样检测也许会有较好的效果提升) SIFT特征 检测的关键就是使用SIFT特征, 首先简单的介绍什么是SIFT特征: SIFT( Distinctive Image Features from Scale-Invariant Keypoints )是一种检测局部特征算法, 该算法通过求一幅图中的特征点(interest points, or corner points)及其有关scale 和 orientation 的描述子得到特征并进行图像特征点匹配, 获得了良好效果, SIFT特征不只具有尺度不变性, 即使改变旋转角度, 图像亮度或拍摄视角, 仍然能够得到好的检测效果. 整个算法分为以下几个部分 尺度空间极值检测 关键点位置及尺度确定 关键点方向确定 特征向量生成 那么在利用SIFT提取出局部特征之后, 便可以利用一些算法来做特征点的匹配, 也就是说复制出的图像会有相同的特征点. 这里采用随机抽样一致算法(RANSAC) Ransac算法检测图像复制 RANSAC算法( Random Sample Consensus: A Paradigm for Model Fitting with Apphcatlons to Image Analysis and Automated Cartography )的基本假设是样本中包含正确数据(inliers, 可以被模型描述的数据), 也包含异常数据(outliers, 偏离正常范围很远、无法适应数学模型的数据), 即数据集中含有噪声. 这些异常数据可能是由于错误的测量、错误的假设、错误的计算等产生的. 同时RANSAC也假设, 给定一组正确的数据, 存在可以计算出符合这些数据的模型参数的方法. 下面简述如何利用RANSAC算法检测直接复制图像类型的篡改. RANSAC是由3步组成: 1, 选择随即选3组以上的匹配的关键点, \\(p_i,\\enspace q_i,\\enspace i \\ge 3\\) 2, 优化 \\(||p_i - (q_i + t)||^2\\) , 其中 \\(t\\) 是变换矩阵. 3, 所有剩余的关键点被分类为内点, 既根据 \\(||p_i - (q_i + t)||^2\\) 是否小于设定阈值. 这样RANSAC算法就能就能将一系列内点归为一类 如果图像被其他修改过, 那么就可以简单的拓展一下便可以再次利用, 也就是修改loss为 \\(||p_i - M(q_i + t)||^2\\) , 其中 \\(M\\) 是一个2*2的变换矩阵. 最终结果如下","tags":"Digital Image Forensics","url":"/forensics_3_2.html","loc":"/forensics_3_2.html"},{"title":"IOS逆向 CCCrypt技巧","text":"CCCrypt原型接口 由于IOS/OSX相对闭源, 故⼤多数算法都是使⽤ObejectiveC 封装的⼀套Crypto库. 该库拥有⼀套统⼀的调⽤ ⼊⼝ CCCrypt. 其具体定义如下 CCCryptorStatus CCCrypt ( CCOperation op , CCAlgorithm alg , CCOptions options , const void * key , size_t keyLength , const void * iv , const void * dataIn , size_t dataInLength , void * dataOut , size_t dataOutAvailable , size_t * dataOutMoved ) # 参数意义 op : kCCEncrypt ( 加密 ) / kCCDecrypt ( 解密 ) alg :加密算法 options :加密⽅式 key :加密密钥 keyLength :密钥⻓度 iv :初始化向量 dataIn :加密数据 dataInLength :加密数据⻓度 dataOut :加密结果 dataOutAvailable :缓冲区⼤⼩ dataOutMoved :加密结果⼤⼩ # 部分参数 Enum列表 # alg enum { kCCAlgorithmAES128 = 0 , kCCAlgorithmAES = 0 , kCCAlgorithmDES , kCCAlgorithm3DES , kCCAlgorithmCAST , kCCAlgorithmRC4 , kCCAlgorithmRC2 , kCCAlgorithmBlowfish } ; typedef uint32_t CCAlgorithm ; # options enum { /* options for block ciphers */ kCCOptionPKCS7Padding = 0 x0001 , kCCOptionECBMode = 0 x0002 /* stream ciphers currently have no options */ } ; typedef uint32_t CCOptions ; # keyLength enum { kCCKeySizeAES128 = 16 , kCCKeySizeAES192 = 24 , kCCKeySizeAES256 = 32 , kCCKeySizeDES = 8 , kCCKeySize3DES = 24 , kCCKeySizeMinCAST = 5 , kCCKeySizeMaxCAST = 16 , kCCKeySizeMinRC4 = 1 , kCCKeySizeMaxRC4 = 512 , kCCKeySizeMinRC2 = 1 , kCCKeySizeMaxRC2 = 128 , kCCKeySizeMinBlowfish = 8 , kCCKeySizeMaxBlowfish = 56 , } ; 利用Frida 快速返回CCCrypt相关调用信息 首先运行命令 frida-trace -U -p 14534 -i \"CCCrypt\" 生成一个默认脚本, 随后修改脚本使之能够返回更多信息. 脚本如下 /* * Auto-generated by Frida. Please modify to match the signature of CCCrypt. * This stub is currently auto-generated from manpages when available. * * For full API reference, see: http://www.frida.re/docs/javascript-api/ */ { /** * Called synchronously when about to call CCCrypt. * * @this {object} - Object allowing you to store state for use in onLeave. * @param {function} log - Call this function with a string to be presented to the user. * @param {array} args - Function arguments represented as an array of NativePointer objects. * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8. * It is also possible to modify arguments by assigning a NativePointer object to an element of this array. * @param {object} state - Object allowing you to keep state across function calls. * Only one JavaScript function will execute at a time, so do not worry about race-conditions. * However, do not use this to store function arguments across onEnter/onLeave, but instead * use \"this\" which is an object for keeping state local to an invocation. */ onEnter : function ( log , args , state ) { log ( 'CCCrypt(' + 'op=' + args [ 0 ] + ', alg=' + args [ 1 ] + ', options=' + args [ 2 ] + ', key=' + args [ 3 ] + ', keyLength=' + args [ 4 ] + ', iv=' + args [ 5 ] + ', dataIn=' + args [ 6 ] + ', dataInLength=' + args [ 7 ] + ', dataOut=' + args [ 8 ] + ', dataOutAvailable=' + args [ 9 ] + ', dataOutMoved=' + args [ 10 ] + ')' ); // 保存参数 this . operation = args [ 0 ] this . CCAlgorithm = args [ 1 ] this . CCOptions = args [ 2 ] this . keyBytes = args [ 3 ] this . keyLength = args [ 4 ] this . ivBuffer = args [ 5 ] this . inBuffer = args [ 6 ] this . inLength = args [ 7 ] this . outBuffer = args [ 8 ] this . outLength = args [ 9 ] this . outCountPtr = args [ 10 ] // this . operation == 0 if ( this . operation == 0 ) { // 打印加密前的原文 console . log ( \"In buffer:\" ) console . log ( hexdump ( ptr ( this . inBuffer ), { length : this . inLength . toInt32 (), header : true , ansi : true } )) // 打印密钥 console . log ( \"Key: \" ) console . log ( hexdump ( ptr ( this . keyBytes ), { length : this . keyLength . toInt32 (), header : true , ansi : true } )) // 打印 IV console . log ( \"IV: \" ) if ( this . ivBuffer != 0 ) { console . log ( hexdump ( ptr ( this . ivBuffer ), { length : this . keyLength . toInt32 (), header : true , ansi : true } )) } else { console . log ( \"None\" ) } } } , /** * Called synchronously when about to return from CCCrypt. * * See onEnter for details. * * @this {object} - Object allowing you to access state stored in onEnter. * @param {function} log - Call this function with a string to be presented to the user. * @param {NativePointer} retval - Return value represented as a NativePointer object. * @param {object} state - Object allowing you to keep state across function calls. */ onLeave : function ( log , retval , state ) { if ( this . operation == 1 ) { // 打印解密后的原文 console . log ( \"out buffer:\" ) console . log ( hexdump ( ptr ( this . outBuffer ), { length : this . outLength . toInt32 (), header : true , ansi : true } )) // 打印密钥 console . log ( \"Key: \" ) console . log ( hexdump ( ptr ( this . keyBytes ), { length : this . keyLength . toInt32 (), header : true , ansi : true } )) // 打印 IV console . log ( \"IV: \" ) if ( this . ivBuffer != 0 ) { console . log ( hexdump ( ptr ( this . ivBuffer ), { length : this . keyLength . toInt32 (), header : true , ansi : true } )) } else { console . log ( \"None\" ) } } } } 将上述代码保存后, 利⽤frida对⽬标应⽤进⾏插桩处理, 并调⽤该脚本, 便可以⾃动化处理使⽤该应⽤ frida-trace -U -p 14534 -i \"CCCrypt\"","tags":"SoftwareSecurity","url":"/ios_cccrypt.html","loc":"/ios_cccrypt.html"},{"title":"数字图像取证 - 基于像素的取证 1","text":"重采样 多数的图像篡改都需要如下步骤:裁剪缩放, 旋转以及拉伸. 上述的操作都需要对图像重采样才可以. 经过这种重采样是基本不可见的,但是这里介绍一种特殊的相关性计算算法. 假设具有 \\(m\\) 个采样点的1-D离散采样信号 \\(f(x, y)\\) , 如图(a). 对其进行重采样时, 无论基于系数 \\(\\frac{p}{q}\\) 将其重采样至n个样本时都需要经过以下三个步骤: 上采样: 新建一个有 \\(pm\\) 个采样的信号 \\(f_u(x)\\) , 其中 \\(f_u(px) = f(x), x = 1, 2, ..., m, 反之 $f_u(x) = 0\\) . 如图(b) 插值: 一个低通过滤卷积信号 \\(f_i(x) = f_i(x) = f_u(x) * h(x)\\) . 如图(c) 下采样: 新建一个有 \\(n\\) 个采样的信号 \\(f_d(x)\\) , 其中 \\(f_d(x) = f_i(qx), t = 1, 2, ..., n\\) . 为后续书写简单, 令 \\(g(x)\\equiv f_d(x)\\) 插值矩阵 如果在第二步中(插值算法)使用的是线性的插值算法,那么重采样过程可以被抽象为 \\(g = A_{{p}/{q}}f\\) ,其中 \\(A\\) 就是插值矩阵,如果使用4/3的权重进行上采样插值那么A就表示为 $$ A_{4/3} = \\begin{bmatrix} 1 & 0 & 0 & 0 &\\\\ 0.25 & 0.75 & 0 & 0 &\\\\ 0 & 0.5 & 0.5 & 0 &\\\\ 0 & 0 & 0.75 & 0.25 &\\\\ 0 & 0 & 0 & 1 &\\\\ & & & & \\ddots \\\\ \\end{bmatrix} $$ 同理对于权重为2的上采样插值算法, 其矩阵组成形式如下 $$ A_{4/3} = \\begin{bmatrix} 1 & 0 & 0 & \\\\ 0.5 & 0.5 & 0 & \\\\ 0 & 1 & 0 & \\\\ 0 & 0.5 & 0.5 & \\\\ 0 & 0 & 1 &\\\\ & & & \\ddots \\\\ \\end{bmatrix} $$ 对于重采样后的信号其值是相邻点的平均值 \\(g_{2i} = 0.5f_i + 0.5f_{i+1}\\) , 其中 \\(i = 1, ..., m-1\\) , \\(f\\) 是原始信号, \\(g\\) 是重采样信号. 因为 \\(f_i = g_{2i - 1}, f_{i + 1} = g_{2i +1}\\) , 故 \\(g_{2i} = 0.5g_{2i - 1} + 0.5g_{2i + 1}\\) . 求解插值矩阵 假设其权重为 \\(p/q\\) , 插值算法则定义为 $$ g_i \\overset{?}{=} \\sum^N_{k = -N} \\alpha_k g_{i + k} $$ 其中 \\(\\alpha_k\\) 为标量权重( \\(\\alpha_0 = 0\\) ). 上式又等价于 $$ \\begin{aligned} g_i - \\sum^N_{k = -N} \\alpha_k g_{i + k} = 0 \\\\ (a_i \\cdot f) - \\sum^N_{k = -N} \\alpha_k (a_{i + k} \\cdot f) = 0 \\\\ (a_i - \\sum^N_{k = -N} \\alpha_k (a_{i + k}) \\cdot f) = 0 \\\\ \\end{aligned} $$ 其中 \\(a_i\\) 是重采样矩阵 \\(A_{p/q}\\) 的第 \\(i^{th}\\) 行, \\(f\\) 是原始信号 因为重采样信号的第 \\(i\\) 个样本与其邻域线性相关. 那么CFA校验类似, 同样的可以使用EM算法对插值矩阵进行预测性. 在E-step 利用 $$ r_1(i) = g_i - \\sum^N_{k = -N} \\alpha_k g_{i + k} $$ 求解似然函数 $$ \\omega_1(i) = P_r(\\alpha | r_1(x, y)) = \\frac{e^{-r^2_1(i)/\\mu}}{e^{-r^2_1(i)/\\mu} + 1/\\sigma} $$ 在M-step最小化 $$ E(\\alpha) = \\sum_i\\omega(i)(g_i - \\sum^N_{k = -N}\\alpha_k g_{i + k}) $$ 最后令梯度为0, 得到 $$ \\alpha = (G^TWG)^{-1}G^TWg $$ 如果 \\(N = 2, g = (g_3, g_4, g_5, ...)^T\\) , \\(W\\) 为权重矩阵的对角矩阵, 矩阵G为 $$ \\begin{bmatrix} g_1 & g_2 & g_4 & g_5 \\\\ g_2 & g_3 & g_5 & g_6 \\\\ g_3 & g_4 & g_6 & g_7 \\\\ \\vdots & \\vdots & \\vdots & \\vdots \\\\ \\end{bmatrix} $$","tags":"Digital Image Forensics","url":"/forensics_3_1.html","loc":"/forensics_3_1.html"},{"title":"数字图像取证 - 基于相机属性的取证 3","text":"PRNU 相机可以简单的建模为 \\(I(x, y) = I_0(x, y) + \\gamma I_0(x, y)K(x, y) + N(x, y)\\) ,其中为 \\(I_0\\) 无噪声的图像, \\(y\\) 是叠加系数, \\(N\\) 是其他噪声因素(灰尘,曝光时间过长等等), \\(K\\) 就是本节中的相机噪声,更具体的指的是photo-response non-uniformity noise(PRNU)为光子(Cmos接受量)与电子(Cmos自有量)的相互干扰产生的一种具有特点性质的噪声。 PRNU提取 PRNU的提取比较简单, 首先提取总噪声 \\(W_k(x, y) = I_k(x, y) - \\hat{I_k}(x, y)\\) . 随后便有 $$ K(x, y) = \\frac{\\sum^n_{k = 1}W_k(x, y)I_k(x, y)}{\\sum^n_{k = 1}I^2_k(x, y)} $$ 图像间的PRNU检测 求解相关性算法, 可以检测两组图像是否使用同一相机进行拍摄. $$ \\rho = I(x, y)k(x, y)\\bigotimes W(x, y) $$ 其中 \\(\\bigotimes\\) 表示正则化的相关性","tags":"Digital Image Forensics","url":"/forensics_2_3.html","loc":"/forensics_2_3.html"},{"title":"数字图像取证 - 基于相机属性的取证 2","text":"CA 理想状态下光线透过滤镜聚焦到传感器上,传感器将光子转储为颜色信息并保存。然而实际上不存在一种滤镜能够完美的将所有波长的光聚焦于传感器上,从而导致导致高光区域与低光区域出现带有颜色的边缘。这一现象被称为CA或色差或紫边(摄影)。由于相机以及镜头的不同,篡改图像的过程中,就会出现色差问题不一致的问题,那么利用这一特性就可以校验图像是否被篡改。首先介绍一下为何会出现色差现象 有折射定律: 1. 折射光线位于入射面内. 2. \\(n\\sin I = n' \\sin I'\\) 注: \\(I\\) 表示入射角, \\(I'\\) 表示折射角,n表示折射率. 以及短波(蓝色)折射率高,长波(红色)折射率低. 根据折射定律由于不同的波长在同一种介质中的折射率不同就会出现如下的情况 建模CA向量 根据折射定律 \\(nsin(\\theta) = n_r\\sin(\\theta_r)\\) 以及 \\(nsin(\\theta) = n_b\\sin(\\theta_b)\\) 得出 \\(n_r\\sin(\\theta_r) = n_b\\sin(\\theta_b)\\) , 进一步的则有 $$ \\begin{aligned} \\frac{n_r\\sin(\\theta_r)}{\\cos(\\theta_b)} &= n_b\\tan(\\theta_b) \\\\ &= \\frac{n_b x_b}{f} \\end{aligned} $$ 其中 \\(f\\) 是透镜至传感器的距离. 但一般而言, 折射角与入射角的偏差很小, 故 $$ \\begin{aligned} n_r\\sin(\\theta_r) &\\approx \\frac{n_b x_b}{f} \\\\ n_r\\tan(\\theta_r) &\\approx \\frac{n_b x_b}{f} \\\\ \\frac{n_r x_r}{f} &\\approx \\frac{n_b x_b}{f} \\\\ n_r x_r &\\approx n_b x_b \\\\ x_r &\\approx \\alpha x_b \\end{aligned} $$ 其中 \\(\\alpha = \\frac{n_b}{n_r}\\) 对于二维图像, 那么便有 \\((x_r, y_r) \\approx \\alpha(x_b, y_b)\\) . 利用该公式可以构造出一组向量 \\(v = (x_r - x_b, y_r - y_b)\\) , 将其拓展至全图, 则会得到如下的概念图 因为图像裁剪的问题存在, 一张图像的光线入射中心并不一定是图像的正中心, 所以该向量还可以建模为 $$ \\bigg\\lbrace{ \\begin{aligned} x_r = \\alpha(x_b - x_0) + x_0 \\\\ x_r = \\alpha(x_b - x_0) + x_0 \\\\ \\end{aligned} } $$ 由于不同镜头的折射率不尽相同, 并且取证是不能获取其所有信息. 故建立一个参数模型对色彩的扭曲进行估算. 估计色差 求解中心点基于互信息最大化来求解 \\(\\argmax_{x1, y1, \\alpha{1} }I{R; G}\\) . 其中R与G是红色通道 \\(R(x, y)\\) 以及绿色通道 \\(G(x, y)\\) 中的随机点. 基于暴力破解法求解 $$ I(R, G) = \\sum_{r \\in R}\\sum{g \\in G}Pr(r, g)log(\\frac{Pr(r, g)}{Pr(r)Pr(g)}) $$ 其中 \\(P(\\cdot , \\cdot)\\) 是联合概率分布, \\(P(\\cdot)\\) 是边缘概率分布 作者同时还提出了验证估计出的参数的方法. 这一模块与取证无关, 简述一下其思想以及方法. 令 \\(x_0, y_0, \\alpha_0\\) 为真实参数, \\(x_1, y_1, \\alpha_1\\) 则为预估出的参数. 那么则有2组CA向量 $$ \\begin{aligned} \\overrightarrow{v_0}(x, y) = \\begin{pmatrix} (\\alpha_0(x - x_0) + x_0) - x\\\\ (\\alpha_0(y - y_0) + y_0) - y\\\\ \\end{pmatrix}\\\\ \\overrightarrow{v_1}(x, y) = \\begin{pmatrix} (\\alpha_1(x - x_1) + x_1) - x\\\\ (\\alpha_1(y - y_1) + y_1) - y\\\\ \\end{pmatrix} \\end{aligned} $$ 随后求解两向量之间的角度误差 $$ \\theta(x, y) = \\cos^{-1}(\\frac{\\overrightarrow{v_0}(x, y)\\cdot\\overrightarrow{v_1}(x, y)}{||\\overrightarrow{v_0}(x, y)||\\space||\\overrightarrow{v_1}(x, y)}) $$ 对于全图像素求解角度误差, 即求解 $$ \\bar{\\theta} = \\frac{1}{P}\\sum_{x, y}\\theta(x, y) $$ 图像篡改检测 在篡改图像时,图像总是由另一部分的图片填补或者拼凑而成,这种方式会导致横向色差的不一致。为了找到这种不一致,我们首先假设只有一小块图片是被篡改过的,以及这种篡改不会严重地影响到整张图片的色差估计。所以可以用全局的估计与每个小块做对比,所有与全局估计相悖的像素块都可能被怀疑是篡改过的。 将示例图片划分为300x300的像素块,在没有空间频域信息的情况下得到小块的色差是很难的,所以选择计算每个色块的平均梯度,且只提取梯度最大的50个色块,梯度的计算公式为 $$ \\delta I(x, y) = \\sqrt{I^2_x(x, y) + I^2_y(x, y) } $$ 其中 \\( \\begin{aligned} I_x(x, y) = ((I(x, y) * d(x) * p(y)) \\\\ I_y(x, y) = ((I(x, y) * d(y) * p(x)) \\end{aligned} \\) , \\(d(\\cdot)\\) 是一阶微分, \\(p(\\cdot)\\) 是低通滤波器. ) 最上方图片圈出的即是一个色块,第二和第三个图是蓝绿的色差统计,第二张图是对全局的,而第三张图是对单独一块的。最下面一张图是角误差的统计图,误差计算的对象是第二张图和第三张图。平均角误差的统计结果为98%的角误差低于60°,平均角误差为14.8°。这个结果表现出色块色差的估计如果显著的大于60°,那么它可以表示色块中存在篡改痕迹。 参考文献 [1] Exposing digital forgeries through chromatic aberration","tags":"Digital Image Forensics","url":"/forensics_2_2.html","loc":"/forensics_2_2.html"},{"title":"数字图像取证 - 基于相机属性的取证 1","text":"CFA 在数字图像中,CFA是位于图像传感器之前的一组用于过滤色彩,收集色彩信息的镜片。由于数码相机传感器仅测量光线的明亮程度无法对色彩做出处理,通过CFA为每一个像素赋予其色彩。 下图是Bayer Array CFA也是最常见的CFA, 使用该CFA导致了实际只有1/3的色彩信息能被cmos保存下来,另外的2/3只能利用插值算法进行填充得来的。那么不同的相机之间由于不同的cmos以及插值算法就会有不同的特征存在。 对于一张Raw图像其每个像素点的RGB构造方式为 $$ \\begin{aligned} \\tilde{R}(x, y) &= S(x, y) &if S(x, y) = r_{x, y} \\\\ &= 0 &otherwise\\\\ \\tilde{G}(x, y) &= S(x, y) &if S(x, y) = g_{x, y} \\\\ &= 0 &otherwise\\\\ \\tilde{B}(x, y) &= S(x, y) &if S(x, y) = b_{x, y} \\\\ &= 0 &otherwise\\\\ \\end{aligned} $$ 再结合插值算法,一个RAW图像RGB像素则抽象为 $$ \\begin{aligned} R(x, y) = \\sum^N_{u, v = -N}h_r(u, v)\\tilde{R}(x - u, y -v) \\\\ G(x, y) = \\sum^N_{u, v = -N}h_r(u, v)\\tilde{G}(x - u, y -v) \\\\ B(x, y) = \\sum^N_{u, v = -N}h_r(u, v)\\tilde{B}(x - u, y -v) \\\\ \\end{aligned} $$ 其中 \\(h()\\) 为不同的插值滤波器,如 \\(h = (\\frac{1}{2}, 1, \\frac{1}{2})\\) 就是一个双线性插值算法,对其做一个外积就变成了2维的双线性插值算法。 当然插值算法不仅仅是双线性一种,不同的相机厂商都有不同的插值算法比如基于中位数的,基于梯度的或者基于自适应色彩平面的等等。就是这些不同的滤波方法就导致了不同的色彩下有了特点的统计信息。 下面我们假设存在这样一种插值算法 $$ \\begin{aligned} R(2x + 1, 2y) &= \\frac{R(2x + 1, 2y - 1)}{2} + \\frac{R(2x + 1, 2y + 1)}{2}\\\\ R(2x, 2y + 1) &= \\frac{R(2x - 1, 2y + 1)}{2} + \\frac{R(2x + 1, 2y + 1)}{2}\\\\ R(2x, 2y) &= \\frac{R(2x - 1, 2y - 1)}{4} + \\frac{R(2x - 1, 2y + 1)}{4} \\\\ &+ \\frac{R(2x + 1, 2y - 1)}{4} + \\frac{R(2x + 1, 2y + 1)}{4} \\end{aligned} $$ 也就是说每一个像素都完美的于其周围的像素相关,反而言之某些非插值的图像中的像素不会于其周围的像素相关。进一步的,如果图像被修改,那么由于不同的插值算法的影响,像素的相关性就会被破坏。 但是,由于我们并不知道像素于像素之间是否真的相关或像素于像素之间的相关关系(插值方法)所以我们无法直接的利用上方的方法,但是EM算法可以解决我们什么都不知道的问题。 我们假设f(x)是一组型号,他来自于两组模型,线性插值的m1模型也就是他与其邻居线性相关 \\(f(x) = \\sum^N_{u = -n}\\alpha_u f(x + u)\\) 以及与其邻居不相关的m2模型. 基于EM算法检测CFA插值情况 下面利用EM算法对两组模型进行验证: 在E-step, 利用残差求解似然 \\(\\omega\\) $$ \\begin{aligned} r_1(x) = f(x) -\\sum^N_{u = -N}\\alpha_uf(x + u)\\\\ w_1(x) = P_r(\\alpha | r_1(x)) = \\frac{\\frac{e^-r^2_1(x)}{\\sigma}}{\\frac{e^-r^2_1(x)}{\\sigma} + \\frac{1}{\\delta}} \\end{aligned} $$ 在M-Step, 利用先前求解出的似然 \\(\\omega\\) , 来估计参数 \\(\\alpha\\) . 首先我们利用SE求误差 $$ E(\\alpha) = \\sum_\\alpha \\omega_1(x)(f(x)- \\sum^N_{u = -N}\\alpha_u f(x + u))^2 $$ 随后对误差求梯度并设置梯度为0, 得到 $$ \\alpha = (F^TWF)^{-1}F^TWf $$ 对于图像而言, 即二维数据的情形我们首先假设 $$ f(x) = \\sum^N_{u, v = -n}\\alpha_{u, v} f(x + u, y + v) $$ 随后求解似然 $$ \\omega_1(x, y) = P_r(\\alpha | r_1(x, y)) = \\frac{frac{e^{r^2_1(x, y)}{\\sigma}}}{frac{e^{r^2_1(x, y)}{\\sigma}} + frac{1}{\\sigma}} $$ 计算误差 $$ E(\\alpha) = \\sum_{x, y}\\omega_1(x, y)(f(x, y) - \\sum^N_{u, v = -N}\\alpha_{u, v}f(x + u, y + v))^2 $$ 最后求解 \\(\\alpha\\) $$ \\begin{aligned} \\sum^N_{u, v =-N}\\alpha_{u, v}(\\sum_{x, y}\\omega_1(x, y)f(x + s, y + t)f(x + u, y + v)) = \\\\ \\sum_{x, y}\\omega_1(x, y)f(x + s, y + t)f(x, y) \\\\ \\end{aligned} $$ 利用求解出的a,那么就可以刻画相邻的像素之间的相关概率,见下图,其中左侧是原图,中间是相关概率图,右侧是利用傅里叶变化处理后的概率图 通常经过特定插值算法的图像的傅里叶变换图,都会有明显的傅里叶峰, 在图像中表现为明显的小点. 基于CFA定位被修改区域 实验使用Nikon D100相机拍摄3张1024x1024的图像, 对其使用3x3的二项式插值算法并下采样至512x512以破坏其CFA插值特征. 随后在对图像模拟CFA插值算法, 并于未插值的\"原始\"图像进行拼接。利用EM算法对CFA插值相关性进行计算效果如下. 参考文献 [1] Exposing Digital Forgeries in Color Filter Array Interpolated Images","tags":"Digital Image Forensics","url":"/forensics_2_1.html","loc":"/forensics_2_1.html"},{"title":"数字图像取证 - 基于文件格式的取证 3","text":"JPEG Ghost 上一节中Double JPEG方法可以检测图像是否被二次压缩过。本节内容将定位出具体被二次压缩过的区域。这一技术被称为JPEG Ghost。 前面介绍过一组RAW data存储为JPEG文件格式首先需要进行傅里叶变换随后便进行量化操作。那么假设有一组经由傅里叶变换后的值 \\(c_1\\) 按照 \\(q_1\\) 进行量化。随后进行还原并按照 \\(c_2\\) 进行量化得到 \\(q_2\\) 。如果 \\(q_1=0\\) (也就是不进行二次量化操作)或 \\(q_1=q_2\\) 时 \\(c_1\\) 与 \\(c_2\\) 之间的损失一定是最小的。同时 \\(c_1\\) 与 \\(c_2\\) 之间的损失也会随着 \\(q_1\\) 或 \\(q_2\\) 的增大而增大。根据这样一个特点未经过二次压缩的图像应是一组基本单调上升但在某一点突然下降至0的数据。而经过二次量化的图像则是会出现2个或以上的下降点。如下图 故本例子中第二次量化的等级为23。 Localization 上面提及了JPEG Ghost的概念以及部分表现,这里对这一方法进行详细描述。首先定义JPEG Ghost中的损失 $$ d(x, y, q)=\\frac{1}{3} \\sum_{i=1}^{3}\\left[f(x, y, i)-f_{q}(x, y, i)\\right]^{2} $$ 其中 \\(f(x,y,i),i=(1,2,3)\\) 表示RGB三个通道中的值(即每个通道经过DCT变换后的值), \\(f_q(\\cdot)\\) 表示按照量化等级q进行还原后的数据。 下图是经过二次压缩的JPEG图像原始图像的量化等级为85,而第二次压缩的量化等级为65。那么当q不断增大,损失一定会在65以及85处瞬间变小,同时将损失表示为图像量化等级在65以及85时候会出现明显的黑色(误差为0,表现为黑色) 变体 由于该差异是在频域空间中计算的,那么无法避免频率较高的区域(天空)的损失的显著性会低于高特征区域(草地)。那么引入归一化技术可以在一定程度上减缓这一现象。这一方法主要是将图像分块处理,计算qxq大小的区域的损失随后将其进行归一化 $$ \\delta(x, y, q)=\\frac{1}{3} \\sum_{i=1}^{5} \\frac{1}{b^{2}} \\sum_{b_{x}=0}^{0} \\sum_{b_{y}=0}^{5}\\left[f\\left(x+b_{x}, y+b_{y}, i\\right)-f_{q}\\left(x+b_{x}, y+b_{y}, i\\right)\\right]^{2} $$ 利用Min-Max归一化对其进行处理 $$ d(x, y, q)=\\frac{\\delta(x, y, q)-\\min _{q}[\\delta(x, y, q)]}{\\max _{q}[\\delta(x, y, q)]-\\min _{q}[\\delta(x, y, q)]} $$","tags":"Digital Image Forensics","url":"/forensics_1_3.html","loc":"/forensics_1_3.html"},{"title":"数字图像取证 - 基于文件格式的取证 2","text":"二次量化(double quantization, double JPEG) 前面提到, JEPG是将位图(bit map)进行转制后利用量化操作$q_a(u) = \\lfloor{\\frac{u}{a}}\\rfloor$, 而这一操作明显是一种有损操作. 那么当对任意图像进行修改之时, 还原回得位图必定不完全等于原始得位图, 随后得又一次压缩更会带来一定得损失以及一种特征. 这种特征可以令安全人员检测出该JPEG文件是否进行过二次编辑. 二次量化是指对JEPG文件进行还原时, 量化还原$q^{-1}_a(u) = \\lfloor\\frac{u}{a}\\rfloor\\times a$ 后再一次对图像进行量化, 故该行为可以被写为$q_{ab}(u) =\\lfloor \\lfloor{\\frac{u}{a}}\\rfloor\\frac{a}{b}\\rfloor$ 下面用一组[0, 127]的正态分布数据来进行模拟实验。 In [1]: import numpy as np import matplotlib.pyplot as plt # imports var = np . random . randn ( 256 , 256 , 3 ) #var = var.flatten() print ( \"var_shape: {} \" . format ( var . shape )) print ( \"var_min: {} \" . format ( var . min ())) print ( \"var_max: {} \" . format ( var . max ())) print ( \"rescale normal distribution\" ) var = ( var - var . min ()) / ( var . max () - var . min ()) * 127 print ( \"var_min: {} \" . format ( var . min ())) plt . hist ( var . flatten (), bins = 'auto' ) plt . show () var_shape:(256, 256, 3) var_min:-5.2071984908675155 var_max:4.825354925163632 rescale normal distribution var_min:0.0 一次量化 直方图仍然保持着正态分布的趋势 In [2]: var_3 = np . floor ( var / 3 ); plt . hist ( var_3 . flatten (), bins = 'auto' ); In [3]: var_2 = np . floor ( var / 2 ); plt . hist ( var_2 . flatten (), bins = 'auto' ); 二次量化 二次量化后的图形, 出现了某种特殊的周期性现象 In [4]: var_2 = np . floor ( var / 2 ); var_23 = np . floor (( var_2 * 2 ) / 3 ) plt . hist ( var_23 . flatten (), bins = 'auto' ); In [5]: var_3 = np . floor ( var / 3 ); var_32 = np . floor (( var_3 * 3 ) / 2 ); plt . hist ( var_32 . flatten (), bins = 'auto' ); 按照相同的量化等级二次量化 原始图像仍然保持着正态分布的形状,在原书中并未对该现象进行过讨论。 也就是说经过二次量化的图像(被篡改),经过精心的设计(使用相同的量化等级恢复并压缩)可以使得这一方法并不能完美的适用于各种情况, 更何况是二次压缩实际上只是判断图像被篡改的必要条件。 In [6]: var_3 = np . floor ( var / 3 ); var_33 = np . floor (( var_3 * 3 ) / 3 ); plt . hist ( var_33 . flatten (), bins = 'auto' ); In [7]: var_2 = np . floor ( var / 2 ); var_22 = np . floor (( var_2 * 2 ) / 2 ); plt . hist ( var_22 . flatten (), bins = 'auto' ); 数学证明 下面通过数学方式证明为什么经过2次量化(不同量化指标)的图像出现与原始压缩不同的直方图。 对于下界函数(floor)。$$\\lfloor{z}\\rfloor=m\\Rightarrow m\\leq\\lfloor{z}\\rfloor<m+1$$ 二次量化则存在性质$$v \\leq\\left\\lfloor\\frac{u}{b}\\right\\rfloor \\frac{b}{a}<v+1 \\quad \\Leftrightarrow \\quad \\frac{a}{b} v \\leq\\left\\lfloor\\frac{u}{b}\\right\\rfloor<\\frac{a}{b}(v+1)$$ 当$\\lfloor{\\frac{u}{b}}\\rfloor$为整数时,上式可以利用上界函数(cell)进行改写$$\\left[\\frac{a}{b} v\\right] \\leq\\left\\lfloor\\frac{u}{b}\\right\\rfloor \\leq\\left\\lceil\\frac{a}{b}(v+1)\\right\\rceil- 1$$ 故对于$u_{min}$以及$u_{max}$有 $$ \\left\\lfloor\\frac{u_{\\min }}{b}\\right\\rfloor=\\left\\lceil\\frac{a}{b} v\\right\\rceil \\quad \\Rightarrow \\quad u_{\\min }=\\left\\lceil\\frac{a}{b} v\\right\\rceil b $$ $$ \\left\\lfloor\\frac{u_{\\max }}{b}\\right\\rfloor =\\left[\\frac{a}{b}(v+1)\\right]-1 \\Rightarrow u_{\\max } =\\left(\\left[\\frac{a}{b}(v+1)\\right]-1\\right) b+(b-1)=\\left[\\frac{a}{b}(v+1)\\right] b-1 $$ 对于计算二次量化序列的直方图时令$H_{a b}(v)=\\sum_{u=u_{\\min }}^{u_{\\max }} H(u)$。对于每一个直方图的盒$n(v)$其可以表示为 $$ n(v)=u_{\\max }-u_{\\min }+1=b\\left(\\left\\lceil\\frac{a}{b}(v+1)\\right\\rceil-\\left\\lceil\\frac{a}{b} v\\right\\rceil\\right) $$ 如上$n(v)=n(v+b)$,就此我们证明出其周期性的来源 最后我们用3-2二次量化(即原图量化等级为3,修改后我们按照量化等级为2对其进行压缩)对该方法进行进一步说明 $$ \\begin{aligned} n(3 k+2) &=3\\left(\\left[\\frac{2}{3}(3 k+3)\\right]-\\left[\\frac{2}{3}(3 k+2)\\right]\\right) \\\\ &=3\\left(2 k+2-2 k-\\left[\\frac{4}{3}\\right]\\right) \\\\ &=0 \\end{aligned} $$ 故每$(3k+2)^{nd}$的盒中,其直方图数据为0","tags":"Digital Image Forensics","url":"/forensics_1_2.html","loc":"/forensics_1_2.html"},{"title":"数字图像取证 - 基于文件格式的取证 1","text":"基于文件格式的取证 文件格式(或文件类型)是指电脑为了存储信息而使用的对信息的特殊编码方式,是用于识别内部储存的资料。(摘自百度百科)。 那么计算机为了处理这样特定的编码一定存在一些特定的标识符来对该数据进行解释。利于在JPEG文件格式中,为了使JPEG数据能正常的还原成为位图数据(bitmap), 文件的头中一定存在着某些数据保存了压缩的参数(量化表,傅立叶变换系数等等)。 色彩空间 色彩空间(英语:Color space)是对色彩的组织方式。借助色彩空间和针对物理设备的测试,可以得到色彩的固定模拟和数字表示。色彩空间可以只通过任意挑选一些颜色来定义,比如像彩通系统就只是把一组特定的颜色作为样本,然后给每个颜色定义名字和代码;也可以是基于严谨的数学定义。 同时颜色可以从以下属性取衡量: 1. 亮度(Brightness,value):指的是感官上区域的明暗。 2. 色相(Hue): 指的是色彩的外相,是在不同波长的光照射下,人眼所感觉不同的颜色,如红色、黄色、蓝色等。 3. 色度(Colorfulness):指色彩的纯度,也叫彩度,即颜色的鲜艳程度。从广义上说,黑色、白色以及灰色是\"色度=0\"的颜色。 4. 明度(Lightness):同一种颜色在不同的亮度中会产生不同的颜色感。具体来讲就是相对于周边颜色亮度(发白感) 5. 色品(Chroma):由色度,明度综合决定 6. 饱和度(Saturation):由色度以及亮度综合决定 基本上所有的色彩空间都由上述6个属性组合而来,并且大多都为3元组的形式,比如 Adobe RGB、sRGB,LAB以及一个四元祖色彩空间CMYK, 该色彩空间由Cyan-青,Magenta-洋红,Yellow-黄,blacK-黑。此处缩写使用最后一个字母K而非开头的B,是因为在整体色彩学中已经将B给了RGB的Blue蓝色。 JPEG文件格式 JPEG是一种有损的文件格式但其也是最常用的图像文件格式。构造一张JPEG图像,一般由以下几个步骤构成 1. RGB转换为YCbCr空间。众所周知,大多数的图像数据都是以RGB色彩空间存储的 。YCbCr是一三元组色彩空间由Y-明度(Lightness),Cb-蓝色偏移,Cr-红色偏移构成。YCbCr由于其按照4:1:1的比例进行采样故常用于影像连续处理,或是数字摄影系统中。 利用YCbCr储存色彩可以有效的降低图像的所占比例。 2. 对每组通道进行8*8的划分,并将每个8*8的数据转换为signed integers。 3. 对每个8*8的数据块进行二维离散傅里叶变换,以储存其频域信息。 \\(\\omega_k=\\frac{2k\\pi}{8}\\) , \\(\\omega_l=\\frac{2l\\pi}{8}\\) ,c对应每个通道以及 \\(f_c(m, n)\\) 对应特定的像素点。 $$F_c(\\omega_c, \\omega_l)=\\sum^7_{m=0}\\sum^7_{n=0}f_c(m, n)cos(\\omega_{k}m)cos(\\omega_{l}n)$$ 4. 对频域信息进行量化压缩。 \\(q_c\\) 是对于每个通道都有一个独立的8*8的量化表 $$\\hat{F_c}(\\omega_k,\\omega_l)=\\lfloor\\frac{F_c(\\omega_k,\\omega_l)}{q_c(\\omega_k,\\omega_l)}\\rfloor$$ 5. 最后在利用熵编码法(一般都是用霍夫曼编码)对压缩后的评语信息再次进行压缩。 ```dot digraph G{ rankdir=LR RGB -> YCbCr YCbCr -> 离散傅里叶 离散傅里叶 -> 量化压缩 量化压缩 -> JEPG } ''' EXIF EXIF(Exchangeable image file format)是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。该数据结构一般嵌入在JEPG,TIFF,RIFF文件格式中。 下面是EXIF包含的信息(摘自WIKI)) 项目 信息(举例) 制造厂商 Canon 相机型号 Canon EOS-1Ds Mark III 图象方向 正常(upper-left) 图象分辨率X 300 图象分辨率Y 300 分辨率单位 dpi 软件 Adobe Photoshop CS Macintosh 最后异动时间 2005:10:06 12:53:19 YCbCrPositioning 2 曝光时间 0.00800 (1/125) sec 光圈值 F22 拍摄模式 光圈优先 ISO感光值 100 Exif信息版本 30,32,32,31 图象拍摄时间 2005:09:25 15:00:18 图象存入时间 2005:09:25 15:00:18 曝光补偿(EV+-) 0 测光模式 点测光(Spot) 闪光灯 关闭 镜头实体焦长 12 mm Flashpix版本 30,31,30,30 图象色域空间 sRGB 图象尺寸X 5616 pixel 图象尺寸Y 3744 pixel 取证 结合上面叙述的JEPG以及EXIF信息,若给定一组图像想要确定那些图像来源于那一台相机,我们可以抽取出: 1. 量化表 - 3x8x8共192个数据特征 2. 图像的长宽 - 2个特征值 3. 霍夫曼编码 - 15x2x3共90个数据特征 4. 可选:EXIF信息,一般而言拥有完整的EXIF信息的图像十分容易确定来源 那么一共284个数据特征,可以用来表示一张图像。随后使用简单的LR模型便可以对一张图像进行分类。","tags":"Digital Image Forensics","url":"/forensics_1_1.html","loc":"/forensics_1_1.html"},{"title":"数字图像取证 - 前言","text":"前言 这个系列是对之前的一部分工作的结果的升华。虽然标题名为 Digital Forensics 的笔记, 但实际上该系列实际是对该书的翻译工作(包括个人理解的添加, 部分不重要言语的删除, 以及其他辅助资料的补充)。 Digital Forenscis Dartmouth大学的 farid 教授出版(现以在UCB任职)。全书共10章, 从文件格式到光学系统,基本覆盖了比较经典的数字取证的方法。 图像篡改的历史 图像篡改并非现代技术(Photoshop等电子化工具),实际上仅仅在涅普斯创造相机的十年之后,图像篡改技术便出现了。 下面实际上就是一张实例,由于观念的不同斯大林将其政委从其合照中抹去。 左侧是被修改的图像,右侧是原始图像。 在Photoshop软件出现之前, 人们实际上也是利用Photoshop对胶片图像进行冲洗,调整抑或是篡改,当然这里的photoshop学名叫做暗房。而前面的Photoshop学名应该叫做电子暗房。 如果想要在胶片图像上完成对一个事物则至少需要3个步骤(不包括正常洗胶片的操作) 底片剪拼:用黑卡纸裁成相应形状,在相纸相应部位作遮挡;之后再遮住其他部分,单独将需要补晒的内容进行第二次晒印曝光。对应在Photoshop中则是将目标图像复制改图像的图层之上。 多次曝光:实际上这就是调整对比度的操作。 调整边缘:调虚焦距,或者适当抖动遮盖纸。 对应至Photoshop这则是羽化边缘的操作。 所以无论是老照片抑或是新的照片,都存在篡改的情况,后面我们将要介绍各种数字取证的方法,检测抑或是利用经过篡改的或未篡改的照片。","tags":"Digital Image Forensics","url":"/forensics_0.html","loc":"/forensics_0.html"},{"title":"Chainer教程 1.5 利用预训练模型以及修改预训练模型","text":"利用预训练模型以及修改预训练模型 预训练模型一般是指针对 ImageNet 分类任务中,各个研究人员设计的不同的网络架构以及训练过的该网络架构权重。 一般常见的网络架构族为VGG,ResNet,DenseNet等。 一般的将上述网络族进行适当的修改,可以很快的应用于不同数据集的分类任务中。同时在其他任务中如目标识别,人脸检测中,上述网络架构也同时存在,0这些网络架构会作为骨架(backbone)存在。 Chainer中提供的预训练模型相对不多,仅VGG16,VGG19,GoogleNet,Resnet50,Resnet101,Resnet152等,但其同时提供用于检测的模型Yolo,SDD等。详情见: Pretrain_model 这里对VGG,ResNet,DenseNet进行一下简短的说明,即为何他们成为非常著名的基准框架。 VGG : 由牛津大学的Visual Geometry Group组提出,该架构的最大贡献在于利用2个3*3的卷积来代替5*5的卷积,3个3*3的卷积代替7*7的卷积,从而减少了参数量. 深入了解 ResNet : 由Facebook AI Research的研究院的何凯明提出,该架构的最大贡献为利用残差机制,残差机制是指对于一层中提取的特征$H(x)$与原始输入$x$的差$F(x)=H(x)-x$,然后利用这一关系显式的指定网络的前向传播过程为原始特征$x+$残差$F\\left(x\\right)$,从而使得网络层至少有恒等映射的作用(Identity mapping)(恒等映射指网络不提取任何特征直接向前传递)。该机制利用完成快捷连接(shortcut Connection),下图为快捷链接的说明。 其数学本质可以理解为利用差分去计算微分方程。 深入了解 DenseNet :由Cornell University的Gao Huang提出。该架构的最大贡献在于将每一层(包括输入数据)的特征传递至后续所有层(create short paths from early layers to later layers)从而更好地获取图像特征。 深入了解 使用预训练模型并修改与训练模型 前面提到预训练模型往往针对 ImageNet 分类任务,而我们的任务往往没有那么多的标签以及输入的数据大小也不尽相同,所以我们需要对预训练模型进行一定的修改。这里主要利用VGG对Cifar10任务进行分类 In [2]: import chainer import chainer.functions as F import chainer.links as L import chainer.datasets import matplotlib.pyplot as plt import chainer.optimizers from chainer.dataset import concat_examples from chainer.cuda import to_cpu import numpy as np from chainer.links import VGG16Layers class VGG ( chainer . Chain ): def __init__ ( self , num = 10 , pretrained = \"auto\" ): super ( VGG , self ) . __init__ () with self . init_scope (): self . feature = VGG16Layers ( pretrained ) self . fc = L . Linear ( None , num ) def forward ( self , x ): h = self . feature ( x , layers = [ 'conv5_3' ])[ 'conv5_3' ] #remove all fc y = self . fc ( h ) return y net = VGG () Downloading from https://www.robots.ox.ac.uk/%7Evgg/software/very_deep/caffe/VGG_ILSVRC_16_layers.caffemodel... Now loading caffemodel (usually it may take few minutes) 下面是VGG中所有的层,但是在上面自定义的模型中,我们不需要使用fc6,7,8 所以我们利用在网络流动过程中我们将其流动到conv5_3便完成输出。 In [3]: for layer in L . VGG16Layers () . available_layers : print ( 'layer name : {} ' . format ( layer )) layer name :conv1_1 layer name :conv1_2 layer name :pool1 layer name :conv2_1 layer name :conv2_2 layer name :pool2 layer name :conv3_1 layer name :conv3_2 layer name :conv3_3 layer name :pool3 layer name :conv4_1 layer name :conv4_2 layer name :conv4_3 layer name :pool4 layer name :conv5_1 layer name :conv5_2 layer name :conv5_3 layer name :pool5 layer name :fc6 layer name :fc7 layer name :fc8 layer name :prob 下面的过程基本与上一章相同,但不同的是由于网络层数的增长,我们需要调节我们的Batch size使之符合我们的设备。 In [7]: train , test = chainer . datasets . get_cifar10 ( ndim = 3 ) # set shape as [n,c,x,y] train_iter = chainer . iterators . SerialIterator ( train , 32 ) test_iter = chainer . iterators . SerialIterator ( test , 32 ) In [13]: net . to_gpu () optimizer = chainer . optimizers . Adam () #use default hyperparameters optimizer . setup ( net ) #bind optimizer and model max_epoch = 20 #set hyperparameter here In [15]: while train_iter . epoch < max_epoch : train_batch = train_iter . next () image_train , target_train = concat_examples ( train_batch , 0 , 0 ) # concat_examples can split data to x and y. logit_train = net ( image_train ) #forward step loss = F . softmax_cross_entropy ( logit_train , target_train ) net . cleargrads () loss . backward () #calculate the gradient optimizer . update () if train_iter . is_new_epoch : print ( 'epoch: {:02d} train_loss: {:.04f} ' . format ( train_iter . epoch , float ( to_cpu ( loss . data )),), end = '' ) test_losses = [] test_accuracies = [] while True : test_batch = test_iter . next () image_test , target_test = concat_examples ( test_batch , 0 , 0 ) logit_test = net ( image_test ) loss_test = F . softmax_cross_entropy ( logit_test , target_test ) test_losses . append ( to_cpu ( loss_test . data )) accuracy = F . accuracy ( logit_test , target_test ) accuracy . to_cpu () test_accuracies . append ( accuracy . data ) if test_iter . is_new_epoch : #reset test_iter test_iter . epoch = 0 test_iter . current_position = 0 test_iter . is_new_epoch = False test_iter . _pushed_position = None break print ( 'val_loss: {:.04f} val_accuracy: {:.04f} ' . format ( np . mean ( test_losses ), np . mean ( test_accuracies ))) epoch:13 train_loss:0.2143 val_loss:0.7409 val_accuracy:0.7804 epoch:14 train_loss:0.1999 val_loss:0.7666 val_accuracy:0.7811 epoch:15 train_loss:0.3452 val_loss:0.7551 val_accuracy:0.7910 epoch:16 train_loss:0.0896 val_loss:0.7685 val_accuracy:0.7964 epoch:17 train_loss:0.4523 val_loss:0.7990 val_accuracy:0.7748 epoch:18 train_loss:0.0481 val_loss:0.7746 val_accuracy:0.8009 epoch:19 train_loss:0.3272 val_loss:0.8336 val_accuracy:0.7766 epoch:20 train_loss:0.2465 val_loss:0.8375 val_accuracy:0.8002 没有经过预训练的VGG是十分难以训练的(但resnet等网络相对容易得多),所以这里利用在Imagenet上训练好的模型再次训练,可以看出与之前自己搭建的5层模型相比,准确率上升了百分之20左右","tags":"MachineLearning","url":"/chainer-1-5.html","loc":"/chainer-1-5.html"},{"title":"Chainer教程 1.4 简单的CNN模型","text":"Chainer实现CNN模型 CNN全称卷积神经网络(Convolution neurual networks),其只要由两部分卷积(Conv)与池化(Pooling)组成。 卷积与池化均来源于泛函中的一种数学算子即通过两个函数f和g生成第三个函数的一种数学算子。卷积与池化最大的区别在于卷积需要训练并且卷积的步长为1,池化则不固定。 这里对步长进行一个小的说明,步长是指滤波器(卷积核)在图像上滑动时一次滑动多少单位的剂量,如下图是一个步长为2的卷积。 而池化一般设置为与池化核心大小相同的值,保证池化区域互不相交。 这里再说一个卷积用数学公式的表示方法$f=\\omega*x + \\beta$, 可以看出整体形式与全连接几乎相同,仅添加了一卷积符号。 Chainer 自构建CNN模型 下面利用一个小的自构建模型对Cifar10数据集进行分类 In [31]: import chainer import chainer.functions as F import chainer.links as L import chainer.datasets import matplotlib.pyplot as plt import chainer.optimizers from chainer.dataset import concat_examples from chainer.cuda import to_cpu import numpy as np class simple_bn ( chainer . Chain ): def __init__ ( self , num = 10 ): super ( simple_bn , self ) . __init__ () with self . init_scope (): self . conv1 = L . Convolution2D ( in_channels = None , out_channels = 6 , ksize = 3 , pad = 1 ) self . conv2 = L . Convolution2D ( in_channels = None , out_channels = 24 , ksize = 3 , pad = 1 ) self . conv3 = L . Convolution2D ( in_channels = None , out_channels = 48 , ksize = 3 , pad = 1 ) self . conv4 = L . Convolution2D ( in_channels = None , out_channels = 96 , ksize = 3 , pad = 1 ) self . conv5 = L . Convolution2D ( in_channels = None , out_channels = 256 , ksize = 3 , pad = 1 ) self . bn1 = L . BatchNormalization ( 6 ) self . bn2 = L . BatchNormalization ( 24 ) self . bn3 = L . BatchNormalization ( 48 ) self . bn4 = L . BatchNormalization ( 96 ) self . bn5 = L . BatchNormalization ( 256 ) self . fc = L . Linear ( None , num ) def forward ( self , x ): h = self . conv1 ( x ) h = F . relu ( h ) h = self . bn1 ( h ) h = F . max_pooling_2d ( h , 2 , 2 ) h = self . conv2 ( x ) h = F . relu ( h ) h = self . bn2 ( h ) h = F . max_pooling_2d ( h , 2 , 2 ) h = self . conv3 ( x ) h = F . relu ( h ) h = self . bn3 ( h ) h = F . max_pooling_2d ( h , 2 , 2 ) h = self . conv4 ( x ) h = F . relu ( h ) h = self . bn4 ( h ) h = F . max_pooling_2d ( h , 2 , 2 ) h = self . conv5 ( h ) h = F . relu ( h ) h = self . bn5 ( h ) y = self . fc ( h ) return y # Define a network class In [14]: train , test = chainer . datasets . get_cifar10 ( ndim = 3 ) # set shape as [n,c,x,y] print ( 'shape: {} ' . format ( train [ 1 ][ 0 ] . shape )) train_iter = chainer . iterators . SerialIterator ( train , 128 ) test_iter = chainer . iterators . SerialIterator ( test , 128 ) plt . imshow ( train [ 1 ][ 0 ] . transpose ( 1 , 2 , 0 )) #get iterator of dataset shape:(3, 32, 32) Out[14]: <matplotlib.image.AxesImage at 0x7f22339d61d0> In [22]: net = simple_bn () #instantiate a model net . to_gpu ( 0 ) #Use gpu and 0 is gpu id optimizer = chainer . optimizers . Adam () #use default hyperparameters optimizer . setup ( net ) #bind optimizer and model max_epoch = 20 #set hyperparameter here Chainer框架提供两种训练方式。一种为显式的调用循环,另一种即为将循环封装起来。这里主要利用显示的方法进行训练,因为更加利于在训练网络的过程中添加一些值或其他的东西。如果希望了解封装式的训练方式请进入 trainer 下面是模型的训练过程,需要注意调用concat_examples方法是如果device设置不为None,这数据将会储存与Gpu中。同时该方法会自动把一个batch的数据pad成为统一大小,也就是说如果你原始的image_train中有2组数据大小分别为[3,24,32]以及[3,12,48] 那么所有的数据都会pad成为[3,24,48]的大小 In [ ]: while train_iter . epoch < max_epoch : train_batch = train_iter . next () image_train , target_train = concat_examples ( train_batch , device = 0 , padding = 0 ) # concat_examples can split data to x and y. logit_train = net ( image_train ) #forward step loss = F . softmax_cross_entropy ( logit_train , target_train ) net . cleargrads () loss . backward () #calculate the gradient optimizer . update () if train_iter . is_new_epoch : print ( 'epoch: {:02d} train_loss: {:.04f} ' . format ( train_iter . epoch , float ( to_cpu ( loss . data )),), end = '' ) test_losses = [] test_accuracies = [] while True : test_batch = test_iter . next () image_test , target_test = concat_examples ( test_batch , 0 , 0 ) logit_test = net ( image_test ) loss_test = F . softmax_cross_entropy ( logit_test , target_test ) test_losses . append ( to_cpu ( loss_test . data )) accuracy = F . accuracy ( logit_test , target_test ) accuracy . to_cpu () test_accuracies . append ( accuracy . data ) if test_iter . is_new_epoch : #reset test_iter test_iter . epoch = 0 test_iter . current_position = 0 test_iter . is_new_epoch = False test_iter . _pushed_position = None break print ( 'val_loss: {:.04f} val_accuracy: {:.04f} ' . format ( np . mean ( test_losses ), np . mean ( test_accuracies ))) epoch:05 train_loss:0.0952 val_loss:1.6678 val_accuracy:0.6791 epoch:06 train_loss:0.1923 val_loss:1.8688 val_accuracy:0.6727 epoch:07 train_loss:0.3112 val_loss:2.0504 val_accuracy:0.6691 epoch:08 train_loss:0.2755 val_loss:2.2125 val_accuracy:0.6643 如果需要对模型保存以及加载,则需要使用以下代码 from chainer import serializers serializers.save_npz('where to save',net) serializers.load_npz('where to load',net)","tags":"MachineLearning","url":"/chainer-1-4.html","loc":"/chainer-1-4.html"},{"title":"Chainer教程 1.2 & 1.3 chainer","text":"安装与Demo 本节用于简单介绍如何安装chainer以及利用其完成一个简单的线性回归模型。 安装 chainer的安装比较简单,由于在2.0中cupy从chainer中分离。仅仅cpu版本的安装速度极快即不需要安装cupy。 安装命令如下 pip install chainer;pip install cupy 安装过程如下所示。 Collecting chainer Downloading https://files.pythonhosted.org/packages/12/ed/8b923bc28345c5b3e53358ba7e5e09b02142fc612378fd90986cf40073ef/chainer-5.4.0.tar.gz (525kB) 100% |████████████████████████████████| 532kB 109kB/s Requirement already satisfied: filelock in /home/r08ust/anaconda3/lib/python3.7/site-packages (from chainer) (3.0.10) Requirement already satisfied: numpy>=1.9.0 in /home/r08ust/anaconda3/lib/python3.7/site-packages (from chainer) (1.15.4) Requirement already satisfied: protobuf>=3.0.0 in /home/r08ust/anaconda3/lib/python3.7/site-packages (from chainer) (3.6.1) Requirement already satisfied: six>=1.9.0 in /home/r08ust/anaconda3/lib/python3.7/site-packages (from chainer) (1.12.0) Requirement already satisfied: setuptools in /home/r08ust/anaconda3/lib/python3.7/site-packages (from protobuf>=3.0.0->chainer) (40.6.3) Building wheels for collected packages: chainer Running setup.py bdist_wheel for chainer ... done Stored in directory: /home/r08ust/.cache/pip/wheels/eb/18/d2/5e85cbd7f32026e5e72cc466a5a17fd1939e99ffeeaaea267b Successfully built chainer Installing collected packages: chainer Successfully installed chainer-5.4.0 Collecting cupy Downloading https://files.pythonhosted.org/packages/cd/d6/532e5da87f3b513cd0b98bcbf9a58fb6758598039944c42cb93d13b71a5f/cupy-5.4.0.tar.gz (2.5MB) 100% |████████████████████████████████| 2.5MB 90kB/s Requirement already satisfied: numpy>=1.9.0 in /home/r08ust/anaconda3/lib/python3.7/site-packages (from cupy) (1.15.4) Requirement already satisfied: six>=1.9.0 in /home/r08ust/anaconda3/lib/python3.7/site-packages (from cupy) (1.12.0) Collecting fastrlock>=0.3 (from cupy) Using cached https://files.pythonhosted.org/packages/89/50/e2ca3f37b783975a7e1f4e7d81a62d6fe269254cdfc46610d8fe42a3f38f/fastrlock-0.4-cp37-cp37m-manylinux1_x86_64.whl Building wheels for collected packages: cupy Running setup.py bdist_wheel for cupy ... done Stored in directory: /home/r08ust/.cache/pip/wheels/77/44/1f/138aca0bd8e7dd12d307eb06b595b15de4f92f2223cf95645d Successfully built cupy Installing collected packages: fastrlock, cupy Successfully installed cupy-5.4.0 fastrlock-0.4 In [1]: #Define import here import chainer import chainer.links as L import chainer.functions as F import chainer.optimizers import numpy as np import matplotlib.pyplot as plt chainer的神经网络层定义在chainer.links中,其中包括许多常用的网络层如Conv,BN,Linear,RNN,LSTM等 chainer.functions中定义一些常见的操作(部分不需要训练的层也定义于其中)如Pooling,add还有常用的loss函数 chainer.optimizers 顾名思义定义了大量的优化器 In [2]: #Get data and define networks y = np . array ([[ 0 ],[ 3 * 4 ],[ 2 * 4 ],[ 4 * 4 ],[ 5 * 4 ],[ 7 * 4 ],[ 8 * 4 ],[ 9 * 4 ],[ 12 * 4 ],[ 15 * 4 ]]) . astype ( np . float32 ) x = np . array ([[ 0 ],[ 1 ],[ 2 ],[ 3 ],[ 4 ],[ 5 ],[ 6 ],[ 7 ],[ 8 ],[ 9 ]]) . astype ( np . float32 ) class demo ( chainer . Chain ): def __init__ ( self , num = 1 ): super ( demo , self ) . __init__ () with self . init_scope (): self . fc = L . Linear ( 1 , 1 ) def forward ( self , x ): y = self . fc ( x ) return y net = demo () Chainer在自定义网络结构时可以采用2种方法,一种如上将其包装在一个类中,可以通过调用该类的实例来完成前向传播操作。另一种即不是用类进行封装具体实现如下 net=chainer.Chain(l1L.Linear(1,1), l2=L.Linear(1,1)) def forward(x,model): y=model.l1(x) y=model.l2(y) return y 但总体来讲,两者并没有显著差距 In [3]: #See before trained picture yhat = net ( x ) #eval stage(only forward) yhat = yhat . data . squeeze () # reshape yhat‘s shape from 10*1 to 10 plt . plot ( x , yhat ) # draw a line plt . scatter ( x , y ) # draw some points Out[3]: <matplotlib.collections.PathCollection at 0x7fe502e0f320> In [4]: #define optimizers opt = chainer . optimizers . SGD ( lr = 0.01 ) #define optimizers opt . setup ( net ) #load model to optimizers #train model epoch = 5 for _ in range ( epoch ): yhat = net ( x ) loss = F . mean_squared_error ( y , yhat ) #compute loss net . cleargrads () loss . backward () #compute gradient opt . update () # update weight print ( 'loss: {} ' . format ( loss . data )) loss:892.8599853515625 loss:167.76364135742188 loss:42.485374450683594 loss:20.833375930786133 loss:17.08420181274414 这里说明一些深度学习中的常见模式或者术语: epoch:即模型对数据的重复学习论次数,由于深度学习往往采用梯度下降方法优化模型,仅仅学习一遍无法很好的学习数据集的特征,故设置多轮epoch。epoch 一般由于数据的复杂程度决定。 lr:即学习率。梯度下降的公式可以概况为$\\theta=\\theta-\\alpha\\frac{\\partial L}{\\partial\\theta}$,其中的$\\alpha$便是学习率。详细的教学推荐吴恩达老师的 CS229 中的第二课,其中对梯度下降方法进行了详细的解释。 参数:即模型中的权重如最简单的单变量线性回归模型$y=\\alpha x+\\beta$中$\\alpha,\\beta$就是参数可以通过优化的方法自动的去计算一个合理值 超参数:超参数无法学习,是指示一些无法学习的人为设置的变量的集合。在这个简单的demo中实际上仅有2组超参数,epoch以及lr,实际上随着模型的提升超参数也越来越多,只能通过手动调节的方法不断尝试。 炼丹:深度学习的过程实际上就是炼丹的过程,选取了合适的丹炉(模型结构),相同的原料(数据),相同的丹炉(模型),利用不同的风水(超参数)炼出一个个不相同的丹(预测结果),同时你还不知道原料是如何组合的(神经网络的黑盒性)。后面将介绍利用不同的丹炉,如卷积炉(CNN),递归炉(RNN),生产对抗炉(GAN)等等,炼丹。 In [5]: yhat = net ( x ) yhat = yhat . data . squeeze () plt . plot ( x , yhat ) plt . scatter ( x , y ) Out[5]: <matplotlib.collections.PathCollection at 0x7fe502d3b908> In [ ]:","tags":"MachineLearning","url":"/chainer-1-3.html","loc":"/chainer-1-3.html"},{"title":"Chainer教程 1.1 机器学习简介","text":"机器学习简述 什么是机器学习? Arthur Samuel 定义机器学习为:\"能使得机器有能力进行学习但不需要显式(explicitly)的编程的技术\". Tom Mitchell 定义机器学习为:\"利用与任务T相关的经验E与度量P,来提升度量P的一种计算机程序\"。 举个例子,现有一信用卡盗刷判断问题,我们按照第一个人给出的定义,编写程序时我们人为的选择某些特征如消费金额超过200000且消费地点不为常见消费地点则为盗刷,那么这个程序就不是一种机器学习程序,因为我们显式的进行了编程。 再结合第二个人给出的定义,我们的任务T就是判断一组行为的中有没有盗刷情况,经验E为行为特征(消费金额,消费地点,消费时间等),那么度量P如使用最简单的方法衡量既正确判断数/总数(这个又称为Accuracy)。 所以机器学习就是利用已有的经验E通过某种不是用规则判断的(非显示)方法,提升人任务T的度量P的一种嗯程序 什么时候适合使用机器学习? 我们结合第一个人给出的定义,最容易想到的情况就是显式地编程(规则判定)难以完成这个任务,在结合第二个人给出的定义我们需要有与任务相关的经验E,那么我们就要有合适的数据集,综上适合机器学习的任务应该有如下的特征 - 显式编程难以完成及难以写出合适的规则集 - 有适合与该任务的数据集 - 数据集有经验可获取(即数据集有潜在规则,这也就是为什么图像识别问题中很多都需要特征提取步骤,因为潜在规则难以理解) 机器学习有什么子类 从任务目标T上来讲机器学习分为2类 - 回归问题:从结果上看他给出了一组数值(如房价的预测),从过程中看其就是一组数学计算的集合 - 分类问题:分类又称为逻辑回归,故名思意其就是逻辑回归的基础上添加了逻辑操作,使得其结果逻辑上由数值变为逻辑符号(实际上就是回归问题加上一个阈值判断,或者最大值的分类(一般多用于多分类问题中,如10分类的问题,计算出分类5的概率最高为0.3,尽管其概率没有超过2分类问题中的阈值但我们只看最高的)) 从经验E来讲机器学习分为3类 - 有监督学习: 什么是监督,也就是经验E有对应的标签,比如有3张狗的照片,告诉你前2个是狗让你去判断第三张那么为有监督学习 - 无监督学习(又称为聚类):同上,不给你相关的标签信息,让机器在机器去判断这3张图片是由相似。 - 半监督学习:即部分标签信息不确定","tags":"MachineLearning","url":"/chainer-1-1.html","loc":"/chainer-1-1.html"},{"title":"Chainer教程 - 前言","text":"为什么是Chainer 无他,为手熟尔。接触Chainer大体是在2016年末,那时的主流框架还是Caffe以及Tensorflow。由于实验室中一些工作需要处理大量变长的数据,而Tensorflow本身对变长输入支持不好,后来了解到Chainer框架对变长输入支持不错便一直使用Chainer至今。 下面简单介绍以下Chainer。Chainer是日本创业公司 Preferred Networks 开发的开源项目。该项目完全由Python构建,主要由2部分组成 神经网络框架 Chainer 以及 GPU版的numpy Cupy组成。(在Chainer 2.0版本发布后,cupy从chainer 中独立,后续使用需要单独安装) Chainer与Pytorch chainer与 pytorch 在 nn的设计上基本一致(pytorch的nn fork自 chainer)。那么两种框架之间的迁移是十分方便的。 chainer通过如下方式定义网络架构 import chainer import chainer.functions as F import chainer.links as L class net ( chainer . Chain ): def __init__ ( self ): super ( net , self ) . __init__ () with self . init_scope (): self . conv1 = L . Convolution2D ( in_channels = None , out_channels = 6 , ksize = 3 , pad = 1 ) self . fc = L . Linear ( None , 10 ) def forward ( self , x ): h = self . conv1 ( x ) h = F . relu ( h ) h = F . max_pooling_2d ( h , 2 , 2 ) y = self . fc ( h ) return y , h Pytorch通过如下方式定义网络结构 import torch import torch.nn as nn import torch.nn.functional as F class Net ( nn . Module ): def __init__ ( self ): super ( Net , self ) . __init__ () self . conv1 = nn . Conv1d ( 1 , 128 , 3 , 1 ) self . pool1 = nn . MaxPool1d ( 3 ) self . fc1 = nn . Linear ( 512 , 10 ) def forward ( self , x ): x = self . conv1 ( x ) x = F . leaky_relu ( x ) x = self . pool1 ( x ) x = x . permute ( 0 , 2 , 1 ) #change the 512x1 to 1x512 x = self . fc1 ( x ) return F . log_softmax ( x , dim = 2 ) 可以看出在网络构建过程中两者基本一致。在数据的操作上两者都是numpy like 的API。 个人认为两种框架后续最大的区别在于处理主体的不同,chainer以chain为主体,pytorch以Variable为主体。很难说两者孰优孰劣,但在部分优化特点变量的问题中,Pytorch更为方便。而chainer的优势在于使用更加方便,如不需要去人为的计算每一次的输入(尤其是在全连接 Fully connect,FC中使用)。","tags":"MachineLearning","url":"/chainer-prewod.html","loc":"/chainer-prewod.html"}]};