zoukankan      html  css  js  c++  java
  • delphi 给EXE文件增加区段

    学习 PE 可执行文件格式,用 delphi 实现给 EXE 文件增加区段
    unit uStudyPE;
    
    interface
    uses
      Classes, SysUtils, Windows, uPERec;
    
    type
    
      TImage_Section_headerList = class;
    
      TStudyPE = class
      private
        FFileStream: TFileStream;
        FNewStream: TMemoryStream;
        FImage_Dos_Header: PImage_DOS_Header;
        FImage_NT_Headers: PImage_NT_Headers;
        FImage_Section_HeaderList: TImage_Section_headerList;
      public
        constructor Create;
        destructor Destroy; override;
      public
        procedure LoadPE(AFileName: string);
        property Image_Dos_Header: PImage_DOS_Header read FImage_Dos_Header;
        property Image_NT_Headers: PImage_NT_Headers read FImage_NT_Headers;
        property Image_Section_HeaderList: TImage_Section_headerList read FImage_Section_HeaderList;
      end;
    
      TImage_Section_headerList = class(TList)
      public
        procedure FreeAllItems();
        destructor Destroy; override;
      end;
    
    implementation
    { TStudyPE }
    const
      Image_Dos_Header_len = SizeOf(TImage_dos_header);
      Image_NT_Headers_len = SizeOf(TImage_NT_Headers);
      Image_Section_Header_len = SizeOf(TImage_Section_Header);
    
    constructor TStudyPE.Create;
    begin
      inherited Create;
      New(FImage_Dos_Header);
      New(FImage_NT_Headers);
      FImage_Section_HeaderList := TImage_Section_headerList.Create;
      FNewStream := TMemoryStream.Create;
    end;
    
    destructor TStudyPE.Destroy;
    begin
      Dispose(FImage_Dos_Header);
      Dispose(FImage_NT_Headers);
      FImage_Section_HeaderList.Free;
      FNewStream.Free;
      inherited;
    end;
    
    procedure TStudyPE.LoadPE(AFileName: string);
    var
    
      e_lfanew: DWORD;
      pSecHeader: PImage_Section_header;
      nNumberOfSections: word;
      i: integer;
      nDosStubLen: integer;
      nSizeOfImage: DWORD;
      LImage_Section_header: TImage_Section_Header;
      Rva: DWORD;
      vaSize: DWORD;
    
      SizeOfHeaders: DWORD; // 一般是 $400
      NewSectionSize: DWORD; // 新增区段大小
    
    begin
    
      if Assigned(FFileStream) then
      begin
        FFileStream.Free;
      end;
    
      NewSectionSize := $200;
    
      FFileStream := TFileStream.Create(AFileName, fmOpenRead);
      FFileStream.Read(FImage_Dos_Header^, Image_Dos_Header_len); // 读 DOS 头,64字节
    
      FNewStream.Size := FFileStream.Size + NewSectionSize; // 新文件大小
      FNewStream.Write(FImage_Dos_Header^, Image_Dos_Header_len); // 将 DOS 头写入新文件
    
      e_lfanew := FImage_Dos_Header.e_lfanew; // 获取 Image_NT_Headers 的位置
      nDosStubLen := e_lfanew - Image_Dos_Header_len; // DOS 汇编代码区域长度
    
      // 将 DOS 汇编代码写入新文件,写完后 FFileStream.Position 正好在 Image_NT_Header 的位置上
      FFileStream.Read((Pbyte(FNewStream.Memory) + Image_Dos_Header_len)^, nDosStubLen);
      FNewStream.Position := Image_Dos_Header_len + nDosStubLen;
    
      FFileStream.Read(FImage_NT_Headers^, Image_NT_Headers_len); // 获取 Image_NT_Headers
      SizeOfHeaders := FImage_NT_Headers.Image_Optional_Header32.SizeOfHeaders;
    
      nNumberOfSections := FImage_NT_Headers.Image_File_Header.NumberOfSections; // 区段数量
      FImage_NT_Headers.Image_File_Header.NumberOfSections := nNumberOfSections + 1; // 增加区段数量
    
      nSizeOfImage := FImage_NT_Headers.Image_Optional_Header32.SizeOfImage;
      FImage_NT_Headers.Image_Optional_Header32.SizeOfImage := nSizeOfImage + NewSectionSize; // 修改 EXE 所占内存大小
      FNewStream.Write(FImage_NT_Headers^, Image_NT_Headers_len); // 将 Image_NT_Headers 写入新文件
    
      FImage_Section_HeaderList.FreeAllItems;
    
      for i := 0 to nNumberOfSections - 1 do
      begin
        New(pSecHeader);
        FImage_Section_HeaderList.Add(pSecHeader);
        FFileStream.Read(pSecHeader^, Image_Section_Header_len);
        FNewStream.Write(pSecHeader^, Image_Section_Header_len); // 将各个 Image_Section_Header 写入新文件
      end;
    
      LImage_Section_header := pSecHeader^;
    
      // 给新区段命名
      LImage_Section_header.Name[0] := ord('.');
      LImage_Section_header.Name[1] := ord('N');
      LImage_Section_header.Name[2] := ord('E');
      LImage_Section_header.Name[3] := ord('W');
      LImage_Section_header.Name[4] := ord('T');
      LImage_Section_header.Name[5] := ord('E');
      LImage_Section_header.Name[6] := ord('S');
      LImage_Section_header.Name[7] := ord('T');
    
      // 用最后一个区段作参考计算新增区段的 VirtualAddress,PointerToRawData 的值
      // VirtualAddress 是在EXE中虚拟地址
      // PointerToRawData 新区段在文件中的位置
      Rva := pSecHeader.VirtualAddress;
      vaSize := ((pSecHeader.Misc.VirtualSize + $FFF) div $1000) * $1000;
      LImage_Section_header.VirtualAddress := Rva + vaSize; // 新区段的虚拟地址
    
      Rva := pSecHeader.PointerToRawData;
      vaSize := ((pSecHeader.Misc.VirtualSize + $1FF) div $200) * $200;
      LImage_Section_header.PointerToRawData := Rva + vaSize; // 新区段的文件中的位置
    
      LImage_Section_header.Misc.VirtualSize := NewSectionSize;
      LImage_Section_header.SizeOfRawData := NewSectionSize;
      LImage_Section_header.Characteristics := $50000040; // 区段的属性(读,写,执行)
    
      // 要计算位置是否够放新 Section, 未完成,本例所改的 exe 是可以的。
    
      if ((SizeOfHeaders - FFileStream.Position) < Image_Section_Header_len) then
      begin
        raise Exception.Create('区段位置不够,本Demo无法操作!');
        // 为了简单,所以这样操作了。实际上是可以的,只是每个区段都得重新计算虚拟地址与在文件中的地址
      end;
    
      FNewStream.Write(LImage_Section_header, Image_Section_Header_len); // 将新增 Image_Section_Header 写入新文件
    
      // 将源文件剩下的数据写入新文件
      FFileStream.Seek(SizeOfHeaders, soBeginning);
      FFileStream.Read((Pbyte(FNewStream.Memory) + SizeOfHeaders)^, FFileStream.Size - SizeOfHeaders);
      FNewStream.SaveToFile('new.exe');
    
    end;
    
    { TImage_Section_headerList }
    
    destructor TImage_Section_headerList.Destroy;
    begin
      FreeAllItems;
      inherited;
    end;
    
    procedure TImage_Section_headerList.FreeAllItems;
    var
      p: PImage_Section_header;
    begin
      for p in self do
        Dispose(p);
      Clear;
    end;
    
    end.
    uStudyPE.pas
    unit uPERec;
    
    interface
    uses
      Classes, SysUtils, Windows;
    
    type
     // Windows 单元中有这些结构,而我为了学习,从书上重新操作了一遍
    
      PImage_DOS_Header = ^TImage_DOS_Header;
      TImage_DOS_Header = packed record
        e_magic: WORD; // DOS signature:4D5A ('MZ')
        e_cblp: WORD;
        e_cp: WORD;
        e_crlc: WORD;
        e_cparhdr: WORD;
        e_minalloc: WORD;
        e_maxalloc: WORD;
        e_ss: WORD;
        e_sp: WORD;
        e_csum: WORD;
        e_ip: WORD;
        e_cs: WORD;
        e_lfarlc: WORD;
        e_ovno: WORD;
        e_res: array [0 .. 3] of WORD;
        e_oemid: WORD;
        e_oeminfo: WORD;
        e_res2: array [0 .. 9] of WORD;
        e_lfanew: DWORD; // offset to NT hearder
      end;
    
      TImage_Optional_Header32 = _Image_Optional_Header32;
      TImage_File_Header = _Image_File_Header;
    
      PImage_NT_Headers = ^TImage_NT_Headers;
      TImage_NT_Headers = packed record
        Signature: DWORD; // PE Signature: 50450000 ('PE'00)
        Image_File_Header: TImage_File_Header;
        Image_Optional_Header32: TImage_Optional_Header32;
      end;
    
      PImage_File_Header = ^TImage_File_Header;
      _Image_File_Header = packed record
        Machine: WORD;
        NumberOfSections: WORD;
        TimeDateStamp: DWORD;
        PointerToSymbolTable: DWORD;
        NumberOfSymbols: DWORD;
        SizeOfOptionalHeader: WORD;
        Characteristics: WORD;
      end;
    
    const
      Image_NumberOf_Directory_Entries = 16;
    
    type
    
      TImage_Data_Directory = _Image_Data_Directory;
    
      PImage_Optional_Header32 = ^TImage_Optional_Header32;
      _Image_Optional_Header32 = packed record
        Magic: WORD;
        MajorLinkerVersion: BYTE;
        MinorLinkerVersion: BYTE;
        SizeOfCode: DWORD;
        SizeOfInitializedData: DWORD;
        SizeOfUninitializedData: DWORD;
        AddressOfEntryPoint: DWORD;
        BaseOfCode: DWORD;
        BaseOfData: DWORD;
        ImageBase: DWORD;
        SectionAlignment: DWORD;
        fileAlignment: DWORD;
        MajorOperatingSystemVersion: WORD;
        MinorOperatingSystemVersion: WORD;
        MajorImageVersion: WORD;
        minorImageVersion: WORD;
        MajorSubsystemVersion: WORD;
        MinorSubsystemVersion: WORD;
        Win32VersionValue: DWORD;
        SizeOfImage: DWORD;
        SizeOfHeaders: DWORD;
        checkSum: DWORD;
        Subsystem: WORD;
        DllCharacteristics: WORD;
        SizeOfStackReserve: DWORD;
        SizeOfStackCommit: DWORD;
        sizeOfHeapReserve: DWORD;
        sizeofHeapcommit: DWORD;
        LoaderFlags: DWORD;
        NumberOfRvaAndSizes: DWORD;
        Image_Data_Directory: array [0 .. Image_NumberOf_Directory_Entries - 1] of TImage_Data_Directory;
      end;
    
      _Image_Data_Directory = packed record
        VirtualAddress: DWORD;
        Size: DWORD;
      end;
    const
      Image_SizeOf_Short_Name = 8;
    
    type
    
      TMisc = packed record
        case integer of
          0:(PhysicalAddress: DWORD);
          1:(VirtualSize: DWORD);
      end;
      // 此为 C 语言 union 格式 改写而成
      //
      //  union {
      //         DWORD PhysicalAddress;
      //         DWORD VirtualSize;
      //  } Misc;
      //
      //
    
      PImage_Section_Header = ^TImage_Section_Header;
      TImage_Section_Header = packed record
        Name: array [0 .. Image_SizeOf_Short_Name - 1] of BYTE;
        Misc: TMisc;
        VirtualAddress: DWORD;
        SizeOfRawData: DWORD;
        PointerToRawData: DWORD;
        PointerToRelocations: DWORD;
        PointerToLineNumbers: DWORD;
        NumberOfRelocations: WORD;
        NumberofLineNumbers: WORD;
        Characteristics: DWORD;
      end;
    
    implementation
    end.
    uPERec.pas
  • 相关阅读:
    django大全
    centos 下安装python3.6.2
    爬虫基础知识与简单爬虫实现
    HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)
    ZOJ5833 Tournament(递归打表)
    ZOJ4067 Books(贪心)
    ZOJ4062 Plants vs. Zombies(二分+贪心)
    ZOJ4060 Flippy Sequence(思维题)
    洛谷P2568 GCD(线性筛法)
    2018.11.6刷题记录
  • 原文地址:https://www.cnblogs.com/lackey/p/8240988.html
Copyright © 2011-2022 走看看