详解二进制文件信息熵Entropy的计算
Posted ybdesire
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解二进制文件信息熵Entropy的计算相关的知识,希望对你有一定的参考价值。
1. 引入
Entropy(熵)能被用于衡量系统的混乱程度,熵值越大,说明混乱程度越高(参考1)。
熵也可以被用在特征工程领域,比如我们提取PE文件的熵值作为一个特征,这种情况下的熵值,一般就说的是“信息熵”。
信息熵也可以被用于衡量PE文件是否加壳(参考2)。PEiD中就有计算熵值的功能,当熵的值超过一定阈值时,则该PE或某段被加壳(Packed)。熵值大,就说明PE文件携带信息量多,就意味着PE文件可能被加壳了。当然,道高一尺魔高一丈,“低熵加壳”又是一个不同的研究方向。
信息熵也可以被用于检测PE病毒(参考3)。当然除了PE文件,其他的二进制文件(比如Mach-O,甚至于pythonscript)也都可以提取并使用信息熵作为特征。
“熵”的计算方式有很多种,包括“信息熵”,“交叉熵”,“相对熵”等等,具体计算过程详见参考4。本文主要讲解“信息熵”的计算,本文提到的“熵”也特指“信息熵”。
2. 信息熵的计算过程举例
信息熵的计算公式如下
其中,H用于表示信息熵的值,它一般是一个float小数。P(i)表示第i个事件发生的概率。
举个例子,假设天气事件的发生有4中可能性:阴、晴、雨、雪;每种事件的发生概率都为1/4,则P(1)=P(2)=P(3)=P(4)=1/4。
则熵值H=-14P(i)*log2(P(i))=2,所以熵值H等于2。这就是信息熵的计算过程。
在这个例子中,每种天气发生的概率都是相等的(都为1/4),此时能求得信息熵的最大值。即“概率均等时,信息熵值最大”,这也是被证明过的定理(证明过程见参考5)
3. 二进制文件信息熵的计算过程
对二进制文件计算信息熵,首先要将文件读入为byte数组,则数组中每个数据值的大小为0~255,具体代码如下:
with open('cfdbbd60c7dd63db797fb27e1c427077ce1915b8894ef7165d8715304756a7e2', 'rb') as fr:
bytez = fr.read()
bytez中就存储了读入的byte数组,举例如下
bytez = b'MZ\\x90\\x00\\x03\\x00\\x00\\x00\\x04'
这个例子中,MZ是PE文件的标识,0x是十六进制数据。这个bytez数组可以转换为如下等效的int数组:
bytez = [77,90,144,0,3,0,0,0,4]
byte数组中有9个数据,字母’M’的ASCII码值为十进制整数77,'Z’的ASCII码值为90。
我们定义P(i)就是byte数组中各个数值为i的概率,则P(77)=1/9, P(90)=P(144)=P(3)=P(4)=1/9, P(0)=4/9。
则
H=-(P(77)*log2(P(77))+P(90)*log2(P(90))+P(144)*log2(P(144))+P(3)*log2(P(3))+P(4)log2(P(4))+P(0)log2(P(0)) ) = -(5(1/9)log2(1/9)+(4/9)log2(4/9)) = -(5(1/9)(-3.169925)+(4/9)(-1.169925)) = 2.28103611
所以,对这段9个数据的byte数组计算得到的熵值为 2.28103611。
4. python编程实现信二进制文件息熵计算
根据上一小节的说明,python计算二进制文件信息熵,要先读入二进制文件为byte数组,再对byte数组计算各个数值出现的概率,最终根据信息熵的计算公式将概率值log计算后乘法累加。完整代码如下:
import math
def H(data):
entropy = 0
for x in range(256):
p_x = data.count(x)/len(data)
if p_x > 0:
entropy += -p_x*math.log(p_x, 2)
return entropy
with open('cfdbbd60c7dd63db797fb27e1c427077ce1915b8894ef7165d8715304756a7e2', 'rb') as fr:
bytez = fr.read()
print('file H',H(bytez))# file H 4.459983287684002
这个例子最终计算得到的结果为4.459983287684002,这说该二进制文件信息熵值为4.459983287684002。
因为二进制文件读入的数据为byte数组,byte数组中每一个元素值的大小为0255,所以上面计算信息熵的函数H()中直接固定了range(256)来计算0255每个数据值出现的概率,这也简化了程序的编程实现。
调用这个H()函数,来对上小节例子中给定的byte数组,代码和结果如下:
bytez1 = b'MZ\\x90\\x00\\x03\\x00\\x00\\x00\\x04'
print('H1',H(bytez1))# 2.2810361125534233
bytez2 = [77,90,144,0,3,0,0,0,4]
print('H2',H(bytez2))# 2.2810361125534233
可以看到,无论是对byte数组bytez1,还是对int数组bytez2,他们的信息熵值都是一样的,这也和上一小节的手工计算结果是完全相等的。
此处使用的信息熵计算H()函数引用自参考6。
5. python第三方库计算信息熵
参考7中有一个pip包pyEntropy可以直接用于计算信息熵,它提供了多种熵值的计算方式
- Shannon Entropy: shannon_entropy
- Sample Entropy: sample_entropy
- Multiscale Entropy: multiscale_entropy
- Composite Multiscale: Entropy composite_multiscale_entropy
- Permutation Entropy: permutation_entropy
- Multiscale Permutation Entropy: multiscale_permutation_entropy
- Weighted Permutation Entropy: weighted_permutation_entropy
调用它提供的shannon_entropy()就能计算信息熵,示例代码如下:
from pyentrp import entropy as ent
# example1: binary file entropy
with open('cfdbbd60c7dd63db797fb27e1c427077ce1915b8894ef7165d8715304756a7e2', 'rb') as fr:
bytez = fr.read()
print('pyentrp H', ent.shannon_entropy(bytez))# 4.459983287684001
# example2: byte array entropy
bytez1 = b'MZ\\x90\\x00\\x03\\x00\\x00\\x00\\x04'
print('pyentrp1', ent.shannon_entropy(bytez1))# 2.2810361125534233
# example3: int list entropy
bytez2 = [77,90,144,0,3,0,0,0,4]
print('pyentrp2', ent.shannon_entropy(bytez2))# 2.2810361125534233
这与第3节手动计算,第4节的python代码计算得到的结果是完全一致的。这也验证了手动计算,python源码计算,第三方库的计算这三种信息熵计算方式结果是一致的。
这个库中计算信息熵的源码见参考8。核心部分的源码解释如下,这和信息熵的计算公式是一致的:
def shannon_entropy(time_series):
data_set = list(set(time_series))#去重
freq_list = []#计算每个数值出现的概率
for entry in data_set:
counter = 0.#每个数值出现的次数
for i in time_series:#统计每个数值出现的次数
if i == entry:
counter += 1
freq_list.append(float(counter) / len(time_series))#每个数值出现的概率
# Shannon entropy,信息熵计算过程
ent = 0.0
for freq in freq_list:#信息熵计算公式
ent += freq * np.log2(freq)
ent = -ent
return ent
6. 总结
本文给出了二进制文件信息熵计算的细节过程示例,细节过程的python源码,以及第三方库的计算方式(核心源码解释)。
参考
- https://zh.wikipedia.org/wiki/%E7%86%B5
- https://www.pediy.com/kssd/pediy11/115515.html
- 基于信息熵的模糊模式识别病毒检测方法研究
- https://charlesliuyx.github.io/2017/09/11/%E4%BB%80%E4%B9%88%E6%98%AF%E4%BF%A1%E6%81%AF%E7%86%B5%E3%80%81%E4%BA%A4%E5%8F%89%E7%86%B5%E5%92%8C%E7%9B%B8%E5%AF%B9%E7%86%B5/
- https://blog.csdn.net/feixi7358/article/details/83861858
- https://github.com/gcmartinelli/entroPy/blob/master/entropy.py#L8
- https://github.com/nikdon/pyEntropy
- https://github.com/nikdon/pyEntropy/blob/master/pyentrp/entropy.py#L80
以上是关于详解二进制文件信息熵Entropy的计算的主要内容,如果未能解决你的问题,请参考以下文章
x264代码剖析(十七):核心算法之熵编码(Entropy Encoding)