⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 upeentry.pas

📁 在delphi中实现windows核心编程.原书光盘代码核心编程.原书光盘代码
💻 PAS
字号:
unit UPEEntry;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, Menus;

type
  {PE导出表声明}
  PImageExportDirectory = ^TImageExportDirectory;
  TImageExportDirectory = packed record
    Characteristics: DWORD;
    TimeDateStamp: DWORD;
    MajorVersion: WORD;
    MinorVersion: WORD;
    Name: DWORD;
    Base: DWORD;
    NumberOfFunctions: DWORD;
    NumberOfNames: DWORD;
    AddressOfFunctions: DWORD;
    AddressOfNames: DWORD;
    AddressOfNameOrdinals: DWORD;
  end;

  PImportByName=^TImportByName;
  TImportByName =Packed  record
    ProcedureHint: word;
    ProcedureName: array[0..1]of char;
  end;

  PImageImportDescriptor = ^TImageImportDescriptor;
  TImageImportDescriptor = packed record
    OriginalFirstThunk: DWord;
    TimeDateStamp  : DWord;
    ForwarderChain : DWord;
    DLLName        : DWord;
    FirstThunk     : DWord;
  end;

  PImageThunkData=^TImageThunkData;
  TImageThunkData = record
  case integer of
    1:( ForwarderString : DWord; );
    2:( Function_       : DWord; );
    3:( Ordinal         : DWord; );
    4:( AddressOfData   : DWord; );
  end;
  PImageBaseRelocation=^TImageBaseRelocation;
  TImageBaseRelocation=Packed Record
     VirtualAddress: Dword;
     SizeOfBlock: Dword;
     TypeOffset: array[0..1] of Word; //不定长
  end;

  TPESection = record    //自定义
    ObjectName: string;
    Address: PChar;
    PhysicalSize: Integer;
//    VirtualSize: Integer;
//    Characteristics: Cardinal;
    PointerToRawData: Integer;
  end;

  TNameOrID = (niName, niID);  
  TPEImport = record
    NameOrID: TNameOrID;
    Name: string;
    ID: Integer;
//    PAddress: PChar; {指向导入表函数用于执行此函数}
  end;
  TPEImports = record {记录一个Dll文件所调用的函数个数}
    DLLName: string;
    Entries: array of TPEImport; {函数数据}
  end;

  TPEExport = record
    Name: string;
    RelativeID: Integer;
    ID: Integer;
    Address: DWORD;{相对地址}
  end;

  TfrmPEEntry = class(TForm)
    GroupBox1: TGroupBox;
    ListBox1: TListBox;
    GroupBox2: TGroupBox;
    ListBox2: TListBox;
    GroupBox3: TGroupBox;
    BitBtn2: TBitBtn;
    procedure BitBtn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PEImports: array of TPEImports;
    PEExport: array of TPEExport;
    Section: array of TPESection;
    procedure Load(FileName:string);
  end;

var
  frmPEEntry: TfrmPEEntry;

implementation

uses UMain;

{$R *.DFM}

procedure TfrmPEEntry.Load(FileName:string);
type
   TImageSectionHeaderArray=array[0..1]of TImageSectionHeader;
   PImageSectionHeaderArray=^TImageSectionHeaderArray;
var
  FileStream: TFileStream;
  ImageDosHeader:TImageDosHeader;
  ImageNtHeaders:TImageNtHeaders;
  ImageBase: PChar;
  FileBase: PChar;
  ImageSize: Integer;
  HeaderSize: Integer;
  NTHeader: PImageNtHeaders;
  I,J: integer;
  ImportEntry: PImageImportDescriptor;
  LookupEntry: PDWord;
  ImportByName: PImportByName;
  SectionTable:PImageSectionHeaderArray;

  ExportEntry: PImageExportDirectory;
  AddressOfFunctions: PChar;
  AddressOfNames: PChar;
  AddressOfNameOrdinals: PChar;
  Found:boolean;
begin
  ListBox1.Clear;
  ListBox2.clear;
  for I := 0 to High(PEImports) do
     SetLength(PEImports[I].Entries, 0);
  SetLength(PEImports,0);
  FileStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  with FileStream do
  begin
    ReadBuffer(ImageDosHeader,sizeof(TImageDosHeader));
    {以下检验是否是合法的PE文件}
    if ImageDosHeader.e_magic<>IMAGE_DOS_SIGNATURE then
    begin
       showmessage('未知的文件格式.');
       FileStream.free;
       exit;
    end;
    if ImageDosHeader._lfanew >= Size then
    begin
       showmessage('未知的文件格式.');
       FileStream.free;
       exit;
    end;
    Position := ImageDosHeader._lfanew;
    ReadBuffer(ImageNtHeaders,sizeof(TImageNtHeaders));
    {检验 NT Header.}
    if ImageNtHeaders.Signature<>IMAGE_NT_SIGNATURE then
    begin
       showmessage('此文件不是WIN32 PE可执行文件.');
       FileStream.free;
       exit;
    end;
    ImageBase:=pointer(ImageNtHeaders.OptionalHeader.ImageBase);
    ImageSize:=ImageNtHeaders.OptionalHeader.SizeOfImage;
    HeaderSize:=ImageNtHeaders.OptionalHeader.SizeOfHeaders;
    {在ImageBaseAdress中分配内存}
    FileBase := VirtualAlloc(ImageBase, ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    {返回映射后的基地址}
    if FileBase = nil then
    begin
       {由系统自动分配内存页}
       FileBase := VirtualAlloc(nil, ImageSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
       if FileBase = nil then
       begin
          showmessage('不能分配内存');
          FileStream.free;
          exit;
       end;
    end;
    Position := 0;
    ReadBuffer(PPointer(FileBase)^, HeaderSize); {读取数据到文件头中}
    {把文件指针定位到NtHeader}
    NTHeader := PImageNtHeaders(FileBase + PImageDosHeader(FileBase)^._lfanew);
    {保存栈}
//    StackCommitSize := NTHeader^.OptionalHeader.SizeOfStackCommit;
    {保存保留栈}
//    StackReserveSize := NTHeader^.OptionalHeader.SizeOfStackReserve;
    {保存切入点}
//    EntryPoint := FileBase + NTHeader^.OptionalHeader.AddressOfEntryPoint;
    {保存代码大小}
//    CodeSize := NTHeader^.OptionalHeader.SizeOfCode;
    {保存代码地址}
//    Code := FileBase + NTHeader^.OptionalHeader.BaseOfCode;
    {保存数据大小}
//    DataSize := NTHeader^.OptionalHeader.SizeOfInitializedData;
    {保存数据地址}
//    Data := FileBase + NTHeader^.OptionalHeader.BaseOfData;
    {从文件中读取信息并保存在变量中}
    SetLength(Section, NTHeader^.FileHeader.NumberOfSections);
    SectionTable:= PImageSectionHeaderArray(longword(NtHeader)+sizeof(TImageNtHeaders));
    for I := 0 to High(Section) do
    begin
       SetLength(Section[I].ObjectName, 8);
       Move(SectionTable^[I].Name, Section[I].ObjectName[1], 8);
       SetLength(Section[I].ObjectName, StrLen(PChar(Section[I].ObjectName)));
       Section[I].PhysicalSize := SectionTable^[I].SizeOfRawData;
//       Section[I].VirtualSize := SectionTable^[I].Misc.VirtualSize;
       Section[I].Address := FileBase + SectionTable^[I].VirtualAddress;
       Section[I].PointerToRawData := SectionTable^[I].PointerToRawData;
       Position := SectionTable^[I].PointerToRawData;
       ReadBuffer(PPointer(Section[I].Address)^, Section[I].PhysicalSize);
//       Section[I].Characteristics := SectionTable^[I].Characteristics;
    end;
    if NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress<>0 then
    begin
       ImportEntry := PImageImportDescriptor(FileBase +
           NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
       {读取导入表入口,直到空为止}
       while ImportEntry^.DLLName <> 0 do
       begin
          {新导入表入口}
          SetLength(PEImports, Length(PEImports) + 1);
          PEImports[High(PEImports)].DLLName := FileBase + ImportEntry^.DLLName;
          if ImportEntry^.OriginalFirstThunk<>0 then
             LookupEntry := PDWord(FileBase + ImportEntry^.OriginalFirstThunk)
          else LookupEntry := PDWord(FileBase + ImportEntry^.FirstThunk);
          {继续读取此Dll直到为空}
          while LookupEntry^ <> 0 do
          begin
             {函数入口}
             SetLength(PEImports[High(PEImports)].Entries, Length(PEImports[High(PEImports)].Entries) + 1);
             with PEImports[High(PEImports)].Entries[High(PEImports[High(PEImports)].Entries)] do
             begin
                if (LookupEntry^ and $80000000) <> 0 then
                begin
                  NameOrID := niID;
                  ID := LookupEntry^ and $7FFFFFFF; {为ID,屏蔽最高位}
                  frmPEEntry.listbox1.items.add(format('函数编号:%-34d 来自的DLL:%-28s 地址:%.8X',[id,PEImports[High(PEImports)].DllName, LookupEntry^]));
                end
                else
                begin
                   NameOrID := niName;
                   ImportByName:=PImportByName(FileBase + LookupEntry^);
                   Name := ImportByName^.ProcedureName; {头两个字节存储ID,其后紧跟为名字}
                   frmPEEntry.listbox1.items.add(format('函数名:%-36s 来自的DLL:%-18s Hint:%.4X 地址:%.8X',[ImportByName^.ProcedureName, PEImports[High(PEImports)].DllName, ImportByName^.ProcedureHint, LookupEntry^]));
                end;
//                PAddress := PChar(LookupEntry);
             end;
             Inc(LookupEntry);
          end; //end with
          Inc(ImportEntry);
       end; //end while
    end;

    if NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress <> 0 then
    begin
       ExportEntry := PImageExportDirectory(FileBase +
            NTHeader^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
       {ExportEntry指向导出表的位置}
       AddressOfNames := FileBase + ExportEntry^.AddressOfNames;
       AddressOfNameOrdinals := FileBase + ExportEntry^.AddressOfNameOrdinals;
       AddressOfFunctions := FileBase + ExportEntry^.AddressOfFunctions;

       {导出的函数的个数}
       setlength(PEExport,ExportEntry^.NumberOfFunctions);
//       FillChar(FList^, FCount * SizeOf(TpeExport), 0);
       for I := 0 to ExportEntry^.NumberOfNames  - 1 do {以名字导出的函数的个数}
       begin
          {保存导出地址}
          PEExport[I].Name := FileBase + PDWord(AddressOfNames + I * 4)^;
          {以ID来查找的导出函数}
          PEExport[I].RelativeID := PWord(AddressOfNameOrdinals + I * 2)^ ;
          PEExport[I].ID := PEExport[I].RelativeID + integer(ExportEntry^.Base-1);
          {函数所处一地址}
          PEExport[I].Address := PDword(AddressOfFunctions + PEExport[I].RelativeID * 4)^;  //相对地址,+FileBase=绝对地址
          listbox2.items.add(format('函数名:%-36s 编号:%.5d 地址:%.8X',[PEExport[I].name,PEExport[I].ID ,Dword(PEExport[I].address)]));
       end;

       for I := 0 to ExportEntry^.NumberOfFunctions - 1 do {搜索以编号导出的函数}
       begin
          Found:=false;
          for J := 0 to ExportEntry^.NumberOfNames - 1 do
          begin
             if I=PEExport[J].RelativeID then //if I+(Base-1)=PEExport[J].ID then
             begin
                Found:=true;
                break;
             end;
          end;
          if not Found then
          begin
             PEExport[I].Name := '';
             PEExport[I].RelativeID := I;
             PEExport[I].ID := PEExport[I].RelativeID + integer(ExportEntry^.Base-1);
             PEExport[I].Address := PDword(AddressOfFunctions + PEExport[I].ID * 4)^;  //相对地址,+FileBase=绝对地址
             listbox2.items.add(format('函数名:%-36s 编号:%.5d 地址:%.8X',['',PEExport[I].ID-integer(ExportEntry^.Base-1) ,Dword(PEExport[I].address)]));
          end;
       end;
    end;
  end;
  VirtualFree(FileBase, 0, MEM_RELEASE);
  FileStream.free;
end;

procedure TfrmPEEntry.BitBtn2Click(Sender: TObject);
begin
  close;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -