• PE文件学习系列笔记四-C++实现PE文件的分析


    合肥程序员群:49313181。    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入)
    Q  Q:408365330     E-Mail:egojit@qq.com

    综述:

    首先说明我也只是PE文件的初学者,我所写的都是自己的学习记录。前3节学习了PE的一些结构,其中包括DOS头和PE头部分。总是这样去学习这些机构和理论的分析我想大家和我一样毫无兴趣,提不起精神。所以我尝试着在自己对PE了解的基础上用C++写一个小程序分析PE结构文件。我所接触的教程都是Win32汇编去实现一些小工具对PE文件进行分析。我只是能看懂汇编,让我去写那没什么劲,所以我还是用C++去实现。我只是对C比较了解,至于面向对象的知识是在学习C#时候接触的。所以这里的案例的C++代码很大的可能还是继承了C的风格。为什么是C++,主要是MFC写界面比Windows API写界面方便多了。当然如果大家有兴趣,可以留言我写一个C#版本的。当然这一节也不可能实现所有的功能,暂时展示一些小功能。废话不多说了,上代码:

    C++代码实现:

    PEc_1

    首先实现这些如图程序的功能,其中包括识别是否是PE文件,其次是给出,PE文件在磁盘中的对齐尺寸和内存中的对齐尺寸,另一个就是实现知道程序的装载入口地址,都是以16进制的方式表现出来的。

    //选择文件按钮
    void CPEinfoDlg::OnBnClickedBtnSelectfile()
    {
        CFileDialog dilog(TRUE);
        dilog.m_ofn.lpstrTitle=_T("请选择PE文件");
        if(IDOK==dilog.DoModal()){
            CString fileName= dilog.GetFileName();
            CString filePath= dilog.GetPathName();
            //给路径文本框赋值
            this->GetDlgItem(IDC_EDIT1)->SetWindowTextW(filePath);
    
    
            HANDLE fileHandle= CreateFile(filePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
            if(INVALID_HANDLE_VALUE!=fileHandle){
                HANDLE mapHandle=    CreateFileMapping(fileHandle,NULL,PAGE_READONLY,0,0,NULL);
                if(mapHandle==NULL){
                    AfxMessageBox(L"打开文件映射对象失败!");
                }
                else
                {
                    strContet= MapViewOfFile(mapHandle,FILE_MAP_READ,0,0,0);
                    LPBYTE lpBaseAddress = (LPBYTE)strContet;
    
                    PIMAGE_DOS_HEADER dosHead=(PIMAGE_DOS_HEADER)lpBaseAddress;
    
                    PIMAGE_NT_HEADERS ntHead=(PIMAGE_NT_HEADERS)(lpBaseAddress+dosHead->e_lfanew);
                    
                    //根据DOS头和PE头判断是否是PE文件
                    if(dosHead->e_magic==IMAGE_DOS_SIGNATURE&&ntHead->Signature==IMAGE_NT_SIGNATURE){
                        //AfxMessageBox(L"说明是正常的PE!");
                        CString show=L"0x";
                        wchar_t r[10]=L"";
                        int h=ntHead->OptionalHeader.FileAlignment;
                        _itow_s(h,r,16);
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_FileA)->SetWindowTextW(show);
                        
                        //内存对齐尺寸
    
                        int ss= ntHead->OptionalHeader.SectionAlignment;
                        _itow_s(ss,r,16);
                        show=L"0x";
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_SESSIONSIZE)->SetWindowTextW(show);
    
                        //入口地址
                        int ept= ntHead->OptionalHeader.AddressOfEntryPoint;
    
                        _itow_s(ept,r,16);
                        show=L"0x";
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_BaseEntry)->SetWindowTextW(show);
    
    
                    }
                    else
                    {
                        AfxMessageBox(L"请打开PE格式文件!");
                    }
    
                    //撤销映射
                    UnmapViewOfFile(strContet);
                    //关闭文件映射对象句柄
                    CloseHandle(mapHandle);
                }
                //关闭文件对象
                CloseHandle(fileHandle);
            }
            else
            {
                AfxMessageBox(L"打开文件句柄失败!");
            }
    
        }
        delete dilog;
        // TODO: 在此添加控件通知处理程序代码
    }

    我就主要上主要代码,当然在这里我们最起码得知道MFC框架的简单开发。

    这些小功能的原理就是读文件,不过我这里用的读文件的方式是文件映射的方式,直接将文件映射到内存中。

    1.首先是打开文件,返回一个文件内核对象(什么是内核对象?这个我就不多做解释了,要想了解请参照《Windows 核心编程》。这绝对是Windows开发的一本葵花宝典),

    HANDLE fileHandle= CreateFile(filePath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);

    2.然后创建一个文件映射对象

    HANDLE mapHandle=    CreateFileMapping(fileHandle,NULL,PAGE_READONLY,0,0,NULL);

    当然是以读方式打开。

    3.然后就是文件内存视图映射

    strContet= MapViewOfFile(mapHandle,FILE_MAP_READ,0,0,0);
    其中strContet是LPVOID类型,这个指针就指向了PE文件被映射到内存中的起始地址

    4.找DOS头和PE头

    PIMAGE_DOS_HEADER dosHead=(PIMAGE_DOS_HEADER)lpBaseAddress;
    
    PIMAGE_NT_HEADERS ntHead=(PIMAGE_NT_HEADERS)(lpBaseAddress+dosHead->e_lfanew);

    PIMAGE_DOS_HEADER 和PIMAGE_NT_HEADERS结构体就是广义上的DOS头和PE头结构。这两个结构体在WinNT.h头文件中能找到。

    5.判断是否是PE文件

    if(dosHead->e_magic==IMAGE_DOS_SIGNATURE&&ntHead->Signature==IMAGE_NT_SIGNATURE)

    就和我们在前面所说的dosHead->e_magic是DOS头的标志,里面是MZ所以DOS头又称作MZ头,ntHead->Signature就是PE头的标志,内容是ASIIC码PE00。我用UE打开:

    PE标志

    在WinNT.h头文件中被定义为IMAGE_DOS_SIGNATURE和IMAGE_NT_SIGNATURE,顾名思义,DOS头标志和PE头标志。这样即使你随便将一个文件修改成.exe后缀或者.dll后缀的PE格式文件依然不通过验证。

    PEyz

    通过这个动态图片我们很容易看到我想打开一个.txt文本这是不行的。我现在去把他改成exe再打开:

    peyz4

    可以看见修改txt后缀为.exe是不行的。

    6.显示内存对齐尺寸程序入口地址等信息

    int h=ntHead->OptionalHeader.FileAlignment;
                        _itow_s(h,r,16);
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_FileA)->SetWindowTextW(show);
                        
                        //内存对齐尺寸
    
                        int ss= ntHead->OptionalHeader.SectionAlignment;
                        _itow_s(ss,r,16);
                        show=L"0x";
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_SESSIONSIZE)->SetWindowTextW(show);
    
                        //入口地址
                        int ept= ntHead->OptionalHeader.AddressOfEntryPoint;
    
                        _itow_s(ept,r,16);
                        show=L"0x";
                        show+=r;
                        this->GetDlgItem(IDC_STATIC_BaseEntry)->SetWindowTextW(show);

    其中没什么复杂度,只是将结构成员数据处理显示出来。这里也验证了。一般PE文件在磁盘中的对齐粒度是200H在内存中的对齐粒度是1000H也就是4K,一分页大小。

    这一节就记到这里,后续的功能等我们学习到的时候再去添加。

    版权:归博客园和Egojit所有,转载请标明出处。
  • 相关阅读:
    apache启用gzip压缩方法--转载自http://www.cnblogs.com/linzhenjie/archive/2013/03/05/2943635.html
    yii 主从数据库分离-转载http://www.yiichina.com/doc/guide/2.0/db-dao
    服装尺寸
    php 同步因子的并发处理
    NFC会员管理-转载自http://technews.cn/2014/09/13/nfc-sticker/
    Redis 利用锁机制来防止缓存过期产生的惊群现象-转载自 http://my.oschina.net/u/1156660/blog/360552
    移动端H5页面的设计稿尺寸大小规范-转载自http://www.chinaz.com/design/2015/1103/465670.shtml
    服饰行业淘宝商城店铺首页设计报告-转载自http://bbs.paidai.com/topic/88363
    网页设计的标准尺寸
    hdu2099
  • 原文地址:https://www.cnblogs.com/egojit/p/3360237.html
Copyright © 2020-2023  润新知