专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »安全 » sql查询分析器:自己写的文件分析器-PE  DeCODER  v1.0 »正文

sql查询分析器:自己写的文件分析器-PE  DeCODER  v1.0

来源: 发布时间:星期六, 2009年9月12日 浏览:82次 评论:0
来源:安全中国

软件Software加密技术这本书里看过PE文件各部分详细解释的后我也有了个自己写PE文件分析器想法虽然好分析器不在少数但对于堆十 6进制数有些朋友可能不明白它代表什么意思如果在里就可以将这些01序列转换成可以直接看懂得信息那至少用户可以省去以后去查表麻烦怀着这样想法我仔细研究了书中分析器PEInfo源代码我发现它没有提供信息转换功能

    通过研究发现PEInfo是通过PE文件在内存中映象来获取文件信息我在想是否还有别思路方法可以绕过将文件映象到内存这直接读取文件信息这样思路方法只有直接读取磁盘上PE文件在磁盘上寻找所需要文件信息

    在这里暂且不说这样做法和内存映象法有什么优劣我在此仅仅只是想找寻另条解决问题道路并实现的看完我分析和源大家自然知道孰优孰劣

    为了避免引起混淆中采用了和PE标准种类似变量名来定义关键数据如文件头可选文件头节表导入表和导出表具体名称定义细节可以在winnt.h里查到整个是以面向过程方式写适当结合了面向对象特征我将读取PE文件信息封装在个对象DataDump里这样是为了方便数据管理和最后输出分析报告而对文件分析则分别有系列来完成现将子介绍说明如下:

//-------------------------------------------------------------------------------------------------------------------

  BOOL Is_EXE_file( stream& PE_file )                       //判断是否是合法PE文件是则返回true否则返回false

  BOOL OutReady( CHAR filename, ofstream& fout )            //输出准备包括输出流和输出文件是则返回true否则返回false

  VOID WriterInfo( ofstream& fout )                           //输出版本信息

  BOOL Load_EXE_Info( stream& PE_file )                     //读取PE文件信息,成功返回true否则返回false

  VOID Decode_EXE_Info(CHAR filename, BOOL IsEXE, stream& PE_file, ofstream& fout)  //分析PE文件信息

  VOID ToNumeric( LPDWORD ptr, CHAR buf, INT start, INT size )   //将从start位开始转换size位为数值放入ptr指向DWORD类型变量中
  
  VOID ( LPSTR ptr, CHAR buf, INT start, INT size)       //从从start位开始取出其后size位放入个ptr指向

//-------------------------------------------------------------------------------------------------------------------

         DataDump 
  {
    private :
    IMAGE_FILE_HEADER FILE_HEADER;                                  // IMAGE_FILE_HEADER 
    IMAGE_OPTIONAL_HEADER32 OPTIONAL_HEADER32;                      // IMAGE_OPTIONAL_HEADER32
    PIMAGE_SECTION_HEADER SECTION_HEADER;                           // PIMAGE_SECTION_HEADER
    IMAGE_IMPORT_DESCRIPTOR IMPORT_DESCRIPTOR;                      // IMAGE_IMPORT_DESCRIPTOR
    PIMAGE_EXPORT_DIRECTORY EXPORT_DIRECTORY;                       // PIMAGE_EXPORT_DIRECTORY

    DWORD ExVRk, ImVRk;                                             // 输出表和输入表在磁盘文件偏移和RVA差值

    public :                                                          // You can get the functions of these member functions below by their names.
    DataDump;
    ~DataDump;

    BOOL Set_FILE_HEADER( CHAR , INT );
    BOOL Set_OPTIONAL_HEADER32( CHAR , INT );
    BOOL Set_SECTION_HEADER32( CHAR , INT );
    BOOL Set_EXPORT_TABLE( CHAR ,  INT );
    
                VOID GetReady( CHAR  );
    DWORD Get_OPTIONAL_HEADER_SIZE( VOID ) const; 
    DWORD Get_SECTION_NUMBER( VOID ) const;
    DWORD Get_EXPORT_TABLE_RAW( VOID ) const;
    DWORD Get_IMPORT_TABLE_RAW( VOID ) const;

    VOID Set_Export_VRk( VOID );
    VOID Set_Import_VRk( VOID );
    BOOL Export_Table_Existed( VOID ) const;
    BOOL Import_Table_Existed( VOID ) const;
    
    BOOL Show_FILE_HEADER( ofstream& ) const;
    BOOL Show_OPTIONAL_HEADER32( ofstream& ) const;
    BOOL Show_SECTION_HEADER32( ofstream& ) const;
    BOOL Show_EXPORT_TABLE( stream&, ofstream& ) const;
    BOOL Show_IMPORT_TABLE( stream&, ofstream& ) const;

  };   
  DataDump pool; 
    
//-------------------------------------------------------------------------------------------------------------------



   DataDump类例子是全局对象这样做是方便子对该对象访问基本思路是在磁盘上打开PE文件判断其是否为合法PE文件否则输出信息退出;是则进行分析包括读取文件头可选文件头节表导入表和导出表将信息储存在DataDump类中最后以txt文件形式输出份文件分析报告

   关键在于文件信息“定位读取”上文件头可选文件头和节表在磁盘上是顺序存放跳过开始PE标志段就可以轻松找到上述几段而且每部分确切大小都在它们相关属性里描述了运行时可以知道读取信息工作很容易就可以完成而输入表和输出表大小是不确定时候会存在没有输入表或没有输出表情况再加上输入输出表出现位置也不固定这会给读取输入输出表工作带来些困难

   我们知道般在PE文件里某项给都是相对虚拟地址RVA并不能直接和磁盘文件物理地址相对应在以内存映象为基础思路方法中只需要取得RVA和ImageBase作简单运算以后就可以定位到某项数据在内存中保存地址而在以直接读取磁盘文件思路方法里必然要涉及到RVA到真实物理地址RAW转换所以对输入输出表读取关键转换到对输入输出表在磁盘文件上定位了

以下是个通用转换思路方法及举例:

+---------+---------+---------+---------+---------+---------+
|  段名称   虚拟地址  虚拟大小  物理地址  物理大小   标志      |
+---------+---------+---------+---------+---------+---------+
|  Name     VOff    VSize    ROff    RSize      Flags |
+---------+---------+---------+---------+---------+---------+
|  .text   00001000   00000092  00000400  00000200  60000020|
|  .rdata  00002000   000000F6  00000600  00000200  40000040|
|  .data   00003000   0000018E  00000800  00000200  C0000040|
|  .rsrc   00004000   000003A0  00000A00  00000400  C0000040|
+---------+---------+---------+---------+---------+---------+
文件虚拟偏移地址和文件物理偏移地址转换公式如下:
FileOff = VA - ImageBase - VRk (VRk是文件虚拟地址和文件物理址的间差值)
           = RVA - VRk

>>>>>>>VaToFileOff(虚拟地址转文件偏移地址)
如VA = 00401000 (虚拟地址)
ImageBase = 00400000 (基地址)
VRk = VOff - ROff = 00001000 - 00000400 = C00 (得出文件虚拟地址和文件物理址的间VRk值)
FileOff = VA - ImageBase - VRk = 00401000 - 00400000 - C00 = 400(文件物理地址偏移地址)

    这样看来关键就在于如何求这个VRk上其实很简单就用节表数据项里面VirtualAddress减去PoerToRawData就可以得到VirtualAddress从字面上看似乎是虚拟地址但其实它也是个RVA是相对于内存映象后首地址偏移而PoerToRawData严格是相对和磁盘文件开始处物理偏移那对输出表VRk来说计算公式应该是这样:
    ExVRk = SECTION_HEADER[i].VirtualAddress - SECTION_HEADER[i].PoerToRawData;
而此时内存和磁盘文件有相同基址即ImBase = RawBase输入表VRk也是相同计算思路方法
    ImVRk = SECTION_HEADER[i].VirtualAddress - SECTION_HEADER[i].PoerToRawData;

    我们首先要找到输入输出表所处区段虽然般以.idata和.edata命名就是输入输出表数据区段旦更改了区段名称就无从查起了在这应该把IMAGE_OPTIONAL_HEADER32中DataDirectory里输入表和输出表VirtualAddress定位到节表中VirtualAddress划分出来区间里就可以找到输入输出表所处区段代码如下:

    for ( INT i=1; i<FILE_HEADER.NumberOfSections; i )
    {
     ( SECTION_HEADER[i].VirtualAddress>OPTIONAL_HEADER32.DataDirectory[0].VirtualAddress  )
    {
      ExVRk = SECTION_HEADER[i-1].VirtualAddress - SECTION_HEADER[i-1].PoerToRawData;
      ;
    }
    }

    接下来对于和输入表相关数据只需要用对应项减去ImVRk就是这项在磁盘文件里偏移如输入表OriginalFirstThunkRVA是00318140只要用这个值减去ImVRk就可以得到OriginalFirstThunk在磁盘文件偏移So is Export Table!

    其他就只剩下如何处理读取数据了我用是C++文件输入流fstream以 2进制形式读进批数据通常都是以相应块大小读入数据如以(IMAGE_FILE_HEADER)然后通过 ToNumeric( LPDWORD ptr, CHAR buf, INT start, INT size )形式变量转换为数值型有时有需要数据就要用( LPSTR ptr, CHAR buf, INT start, INT size)取出特定某几位这些在源代码里都可以看到我在写过程中发现C++输入流不是太稳定时候会读不进数据我在每个涉及到读入数据地方都加了输入流clear它重置了流状态让流始终处于稳定状态下输出分析报告到txt文件我用是C++输出流为了保证输出稳定性我也了输出流clear最后报告会保存在和用户输入可执行文件同名文本文件里

    最后有点申明这个是在Visual C++ 6.0环境下编译在其他C++环境下好像不能编译通过winnt.h版本问题区别编译环境所带winnt.h内容不尽相同在这些环境下编译会出错而且这个可以在32位和64位环境下运行但还不能分析64位应用可能是64位PE32+格式和32位PE格式区别引起我用PEid0.94和stud_PE也不能分析64位应用

    读到这里如果你看完源代码应该可以得到自己结论了哪种思路方法更好目了然但仔细斟酌每种思路方法都有他自己优点和弊病但这不是我所关心事情关键是我在这过程中更加深入理解了PE结构锻炼了自己编程能力欢迎大家发表意见有关有关PEor something 写得仓促在代码可读性上敬请原谅有什么好建议欢迎大家和我联系
    
    E-mail : [email protected]

    写完的后就像高考结束在等待成绩到来段时间放松悠闲别人如何评价已不重要尽力就好!^_^



  • 篇文章: 驱动壳编写整理总结

  • 篇文章: 没有了
  • 0

    相关文章

    读者评论

    发表评论

    • 昵称:
    • 内容: