当前位置:编程学习 > VC++ >>

基于VC++实现PE的修改编程

在Windows系统下的可执行文件的一种(还有NE、LE),是微软设计、TIS(Tool Inte易做图ce Standard,工具接口标准)委员会批准的一种可执行文件格式。PE的意思是Portable Executable(可移植可执行)。所有Windows下的32位或64位可执行文件都是PE文件格式,其中包括DLL、EXE、FON、OCX、LIB和部分SYS文件。
DOS-stub(DOS-头)
  DOS-根的概念很早从16位windows的可执行文件(当时是“NE”格式)时就广为人知了。根原来是用于OS/2系统的可执行文件的,也用于自解压档案文件和其它的应用程序。对于PE文件来说,它是一个总是由大约100个字节所组成的和MS-DOS 2.0兼容的可执行体,用来输出象“This program needs windows NT”之类的错误信息。
  你可以通过确认DOS-头部分是否为一个IMAGE_DOS_HEADER(DOS头)结构来认出DOS-根,它的前两个字节必须为连续的两个字母“MZ”(有一个#define IMAGE_DOS_SIGNATURE的定义是针对这个WORD单元的)。
  你可以通过跟在后面的签名来将一个PE二进制文件和其它含有根的二进制文件区分开来,跟在后面的签名可由头成员'e_lfanew'(它是从字节偏移地址60处开始的,有32字节长)所设定的偏移地址找到。对于OS/2系统和Windows系统的二进制文件来说,签名是一个16位的word单元;对于PE文件来说,它是一个按照8位字节边界对齐的32位的longword单元,并且IMAGE_NT_SIGNATURE(NT签名)的值已由#defined定义为0x00004550(即字母“PE/0/0”)。
file-header(文件头)
  要到达IMAGE_FILE_HEADER(文件头)结构,请先确认DOS-头“MZ”(起始的2个字节),然后找出DOS-根的头部的成员“e_lfanew”,并从文件开始处跳过那么多的字节。在核实你在那里找到的签名后,IMAGE_FILE_HEADER(文件头)结构的文件头就紧跟其后开始了。
optional header(可选头)
  紧跟在文件头后面的就是IMAGE_OPTIONAL_HEADER(尽管它名叫“可选头”,它却一直都在那里)。它包含有怎样去准确处理PE文件的信息。
data directories(数据目录)
  IMAGE_NUMBEROF_DIRECTORY_ENTRIES (16)(映象文件目录项数目)个IMAGE_DATA_DIRECTORY(映象文件数据目录)数组。这些目录中的每一个目录都描述了一个特定的、位于目录项后面的某一节中的信息的位置(32位的RVA,叫“VirtualAddress(虚拟地址)”)和大小(也是32位,叫“Size(大小)”)。
  例如,安全目录能在索引4中给定的RVA处发现并具有索引4中给定的大小。
section headers(节头)
  节由两个主要部分组成:首先,是一个节描述(IMAGE_SECTION_HEADER[意为“节头”]类型的),然后是原始的节数据。因此,我们会在数据目录后发现一“NumberOfSections”个节头组成的数组,它们按照各节的RVA排序。
sections(节数据)
  所有的节在载入内存后都按“SectionAlignment”(节对齐)对齐,在文件中则以“FileAlignment”(文件对齐)对齐。节由节头中的相关项来描述:在文件中你可通过“PointerToRawData”(原始数据指针)来找到,在内存中你可通过“VirtualAddress”(虚拟地址)来找到;长度由“SizeOfRawData”(原始数据长度)决定。
  根据节中包含的内容,可分为好几种节。大多数(并非所有)情况下,节中至少由一个数据目录,并在可选头的数据目录数组中有一个指针指向它。
 
下面我们实现编程修改PE
[cpp]
// Pe.cpp: 实现 CPe类. 
// 
#include "stdafx.h" 
#include "Pe.h" 
 
CPe::CPe() 


 
CPe::~CPe() 


 
void CPe::ModifyPe(CString strFileName,CString strMsg) 

    CString strErrMsg; 
 
    HANDLE hFile, hMapping; 
    void *basepointer; 
     
    // 打开要修改的文件. 
    if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE,  
        FILE_SHARE_READ|FILE_SHARE_WRITE, 0,  
        OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE) 
    { 
        AfxMessageBox("Could not open file."); 
        return; 
    } 
 
    // 创建一个映射文件. 
    if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0))) 
    { 
        AfxMessageBox("Mapping failed."); 
        CloseHandle(hFile); 
        return; 
    } 
 
    // 把文件头映象存入baseointer. 
    if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0))) 
    { 
        AfxMessageBox("View failed."); 
        CloseHandle(hMapping); 
        CloseHandle(hFile); 
        return; 
    } 
 
    CloseHandle(hMapping); 
    CloseHandle(hFile); 
 
    CalcAddress(basepointer); // 得到相关地址. 
    UnmapViewOfFile(basepointer); 
     
    if(dwSpace<50) 
    { 
        AfxMessageBox("No room to write the data!"); 
    } 
    else 
    { 
        WriteFile(strFileName,strMsg); // 写文件. 
    } 
     
    if ((hFile = CreateFile(strFileName, GENERIC_READ|GENERIC_WRITE,  
        FILE_SHARE_READ|FILE_SHARE_WRITE, 0,  
        OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE) 
    { 
        AfxMessageBox("Could not open file."); 
        return; 
    } 
     
    CloseHandle(hFile); 

 
void CPe::CalcAddress(const void *base) 

    IMAGE_DOS_HEADER * dos_head =(IMAGE_DOS_HEADER *)base; 
 
    if (dos_head->e_magic != IMAGE_DOS_SIGNATURE) 
    { 
        AfxMessageBox("Unknown type of file."); 
        return; 
    } 
     
    peHeader * header; 
 
    // 得到PE文件头. 
    header = (peHeader *)((char *)dos_head + dos_head->e_lfanew); 
 
    if(IsBadReadPtr(header, sizeof(*header))) 
    { 
        AfxMessageBox("No PE header, probably DOS executable."); 
        return; 
    } 
 
    DWORD mods; 
    char tmpstr[4]={0}; 
    if(strstr((const char *)header->section_header[0].Name,".text")!=NULL) 
    { 
        // 此段的真实长度. 
补充:软件开发 , Vc ,

CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,