Rock2012′s Blog

07月 15, 2010

用Python写一个程序扫描工具

Filed under: 编程 — rock2012 @ 10:04 am
Tags: , , , ,

有时候我们需要对一个程序文件进行分析,得到这个程序所包含的基本信息,包括PE格式内容,是否packed或执行恶意行为等等。当然,有许多工具可以完成这样的工作。如果我们只想得到特定的信息,而需要分析的程序文件又很多呢?那就动手写一个自己的程序扫描工具吧!使用Python及其第三方工具包,我们可以很轻松的定制出我们自己的扫描工具。我在这篇文章里会拿出一份代码,通过代码的逐步分析来展示出这样一个工具是如何帮助我们完成程序分析的工作。用到的工具包括Python,PeFile,PEID和一个命令行式的恶意软件扫描工具。

首先是开发包的安装:
1.安装Python
2.下载pefile,将得到的压缩包解压到python\lib\site-packages文件夹中
3.在命令行窗口,使用cd命令进入到解压出来的pefile文件夹中,执行python setup.py install
下面,我会使用代码分析的方式描绘出这个工具的工作流程。

## Entropy calculation from Ero Carrera’s blog ############### 
def E(data): 
        entropy = 0   
        if not data: 
                return 0 
        ent = 0 
        for x in range(256): 
                p_x = float(data.count(chr(x)))/len(data
                if p_x > 0: 
                        entropy += - p_x*math.log(p_x, 2
        return entropy

一般来说,程序中的数据越无序,其熵值也越高,这个程序文件被加壳或混淆的可能性也越大。熵值的范围在0.0到8.0之间。更详细的介绍在这里http://blog.dkbza.org/2007/05/scanning-data-for-entropy-anomalies.html。

## Load PEID userdb.txt database and scan file 
def PEID(): 
        signatures = peutils.SignatureDatabase(‘userdb.txt’
        matches = signatures.match_all(pe,ep_only = True
        print “PEID Signature Match(es): “, matches 
        print

PEID的用户数据库(userdb.txt)在这里http://www.peid.info/BobSoft/Downloads.html下载。

## Print Sophos 
def sophos(filetmp): 
        print “Sophos Scan in progress..” 
        output = “None” 
        path = os.path.abspath(filetmp
        pwd = os.getcwd() 
        output = subprocess.call([os.path.join(pwd, 'cmd_scan', 'Sophos', 'SAV32CLI.EXE'), path])

这里用Sophos里包含的命令行式的扫描工具进行程序分析。

其他信息在代码及注释中已经表达得很清楚了。完整的代码如下所示:

## Virustotal Python Scanner script 0.01
## Created by Alexander Hanel

import sys
import os
import math
import time
import datetime
import subprocess
import pefile     #这两个模块都包含在
import peutils    #Pefile中

##############################################################
## Print PE file attributes & metadata
def attributes(): 
        print “Image Base:”, hex(pe.OPTIONAL_HEADER.ImageBase)
        print “Address Of Entry Point:”, hex(pe.OPTIONAL_HEADER.AddressOfEntryPoint)
        machine = 0
        machine = pe.FILE_HEADER.Machine
        print “Required CPU type:”, pefile.MACHINE_TYPE[machine]
        dll = pe.FILE_HEADER.IMAGE_FILE_DLL
        print “DLL:”, dll
        print “Subsystem:”, pefile.SUBSYSTEM_TYPE[pe.OPTIONAL_HEADER.Subsystem]
        print “Compile Time:”, datetime.datetime.fromtimestamp(pe.FILE_HEADER.TimeDateStamp)
        print “Number of RVA and Sizes:”, pe.OPTIONAL_HEADER.NumberOfRvaAndSizes

##############################################################
## Analyze Sections
def sections_analysis():
        print “Number of Sections:”, pe.FILE_HEADER.NumberOfSections
        print
        print “Section  VirtualAddress VirtualSize SizeofRawData Entropy”
        for section in pe.sections:
                print %-8s  % section.Name, %-14s % hex(section.VirtualAddress), %-11s % hex(section.Misc_VirtualSize),\
                      %-13s % section.SizeOfRawData, %.2f % E(section.data)
        print

##############################################################
## Dump Imports
def IAT():
        print “Imported DLLS:”
        i = 1
        for entry in pe.DIRECTORY_ENTRY_IMPORT:
                bool = 1 ## For Formattting
                print %2s % [i], %-17s % entry.dll
                print \t,
                for imp in entry.imports:
                        if bool:
                                print %-1s % imp.name,
                                bool = 0
                        else:
                                sys.stdout.write(%s%s % (“, “,imp.name)) # Python Print adds a blank space
                print
                i += 1
               
##############################################################
## Entropy calculation from Ero Carrera’s blog ###############
def E(data):
        entropy = 0 
        if not data:
                return 0
        ent = 0
        for x in range(256):
                p_x = float(data.count(chr(x)))/len(data)
                if p_x > 0:
                        entropy += - p_x*math.log(p_x, 2)
        return entropy

##############################################################
## Load PEID userdb.txt database and scan file
def PEID():
        signatures = peutils.SignatureDatabase(‘userdb.txt’)
        matches = signatures.match_all(pe,ep_only = True)
        print “PEID Signature Match(es): “, matches
        print

##############################################################
## Print Sophos
def sophos(filetmp):
        print
        print “Sophos Scan in progress..”
        output = “None”
        path = os.path.abspath(filetmp)
        pwd = os.getcwd()
        output = subprocess.call([os.path.join(pwd, 'cmd_scan', 'Sophos', 'SAV32CLI.EXE'), path])
       
## Thanks habnabit
##############################################################

if len(sys.argv) < 2:
        print “Pyton Script <FILE>”
        sys.exit(3)
exename = sys.argv[1]
pe = pefile.PE(exename)
print \nPortable Executable Information”
attributes()
sections_analysis()
PEID()
IAT()
sophos(exename)

## </FILE>  <- Format bug with SyntaxHighlighter (remove line)

来源:http://hooked-on-mnemonics.blogspot.com/2010/04/creating-your-own-virustotal-well-kind.html

使用代码解释Big O概念

Filed under: 编程 — rock2012 @ 6:24 am
Tags:

在计算机科学中,Big O是用来描述算法的性能表现或复杂度的概念。Big O描述了最坏情形下,算法执行所需的时间或空间(比如内存或磁盘)。

O(1)

如果算法的执行总是需要相同的时间(或空间),而与输入数据的规模无关,那这个算法的复杂度为O(1)

bool IsFirstElementNull(String[] strings)
{
    if(strings[0] == null)
    {
        return true;
    }
    return false;
}

O(N)

复杂度为O(N) 的算法,其执行所需的时间或空间呈线性增长并与输入数据的规模成正比。下面的例子说明了Big O应用在最坏情形下:在for循环的任何一次迭代中,匹配的字符串都可能被提前找到并使函数返回,但是Big O概念表示的是最坏情形下的算法复杂度,所以总是假定算法执行上限次数的运行,即最大次数的迭代。

bool ContainsValue(String[] strings, String value)
{
    for(int i = 0; i < strings.Length; i++)
    {
        if(strings[i] == value)
        {
            return true;
        }
    }
    return false;
}

O(N2)

O(N2)表示算法的复杂度与输入数据的规模的平方成正比。这在涉及嵌套循环的算法中常见。更深层次的循环则会使复杂度增加为O(N3), O(N4)……。

bool ContainsDuplicates(String[] strings)
{
    for(int i = 0; i < strings.Length; i++)
    {
        for(int j = 0; j < strings.Length; j++)
        {
            if(i == j) // Don’t compare with self
            {
                continue;
            }
            if(strings[i] == strings[j])
            {
                return true;
            }
        }
    }
    return false;
}

O(2N)

O(2N)则表示算法随输入数据规模的每增加一个,其复杂度也会翻番。其执行时间也会迅速地增加。

对数复杂度O(log N)

下面会通过一个例子说明对数复杂度。

二分法搜索(Binary search)是一项用于搜索已排序数据的技术。它通过选出数据的中项,与目标数值相比较。如果两数值相匹配,则返回成功。如果目标数值大于中项,则取出数据集合中大于中项的部分进行上面的操作。类似地,如果目标数值小于中项,则取出小于中项的部分进行相同的操作。这样,程序不断地二等分分数据集合,直到数值匹配或数据集合无法分解为止。

这种算法被描述为O(log N)。

重复地二等分数据集合的过程,如果绘制成图表,会发现开始时会达到一个顶峰,然后随着数据的增加,曲线会逐渐趋向平缓。使数据集合加倍对效率的影响也会很小,因为在一次迭代之后,所需处理的数据量会减少一半。这样使算法在处理规模较大的数据集合时会非常有效率。

主题: Rubric. 在WordPress.com的博客.

加关注

Get every new post delivered to your Inbox.