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

📄 peheader.dpr

📁 delphi开发语言下的源代码分析
💻 DPR
字号:
// dcc PEHeader -uc:\ext\jedi\api
// COPY/Y C:\ext\ls\Apps\PEHeader\PEHeader.exe c:\dos\peh.exe
// PEHeader e:\delphi7\bin\delphi32.exe
// DLLTools

{$APPTYPE CONSOLE}
{$RANGECHECKS OFF}

uses
  JwaWinNT, windows, classes, SysUtils;

type
  TSectionHeaderArr = array [Word] of TImageSectionHeader;
  PSectionHeaderArr = ^TSectionHeaderArr;
  TSectionName = packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of char;

  TResourceDirectoryEntryArr = array [WORD] of TImageResourceDirectoryEntry;
  PResourceDirectoryEntryArr = ^TResourceDirectoryEntryArr;

  TFunctionRVA = array [0..0] of DWORD;

  _IMAGE_BASE_RELOCATION = record
    VirtualAddress: DWORD;
    SizeOfBlock: DWORD;
    //  WORD    TypeOffset[1];
  end;
  PImageBaseRelocation = ^_IMAGE_BASE_RELOCATION;


var
  p : PByte;
  i, tempSize : Integer;
  Str : pChar;

  pBASE, VABase, RawAddr, sRVA : DWORD;

  ThunkData : DWORD;
  isFileMap : Boolean = true;

  pNameRVA : PDWord;
  pOrdinal: PWord;
  pFunctionRVA : ^TFunctionRVA;

  pRelocItem : PWord;

const
  ResourceTypeArr : array [1..24] of String
                  = ('CURSOR',
                     'BITMAP',
                     'ICON',
                     'MENU',
                     'DIALOG',
                     'STRING',
                     'FONTDIR',
                     'FONT',
                     'ACCELERATOR',
                     'RCDATA',
                     'MESSAGETABLE',
                     'GROUP_CURSOR',
                     'Unknow',
                     'GROUP_ICON',
                     'Unknow',
                     'VERSION',
                     'DLGINCLUDE',
                     'Unknow',
                     'PLUGPLAY',
                     'VXD',
                     'ANICURSOR',
                     'ANIICON',
                     'HTML',
                     'MANIFEST');

//取资源类别, 仅对根级目录有效                     
function GetResourceClass(NameOffset:DWORD) : String;
begin
  case NameOffset of
    low(ResourceTypeArr)..high(ResourceTypeArr) :
      Result := ResourceTypeArr[NameOffset];
  else
    Result := 'Unknow';
  end;
end;

//名字是基于节起点的偏移
function GetNameFromOffset(sRVA, BaseAddr : Integer) : String; overload;
var
  pStr : PImageResourceDirStringU;
  S : WideString;
begin
  Integer(pStr) := BaseAddr + sRVA;
  SetLength(S, pStr^.Length);
  move(pStr^.NameString, S[1], pStr^.Length*2);
  Result := S;
end;

//数据是基于节起点的RVA
function GetStringFromRVA(sRVA, BaseVA, BaseAddr : Integer) : String;
begin
  Result := GetNameFromOffset(sRVA - BaseVA, BaseAddr);
end;

//取资源名
function GetResourceName(NameOffset:DWORD; BaseVA, BaseAddr: Integer) : String;
begin
  if (NameOffset and IMAGE_RESOURCE_NAME_IS_STRING)=0 then
    Result := IntToStr(NameOffset)
  else
    Result := GetNameFromOffset(NameOffset and $7FFFFFFF, BaseAddr);
end;

// BASE = 文件映像在内存中的起始地址
// Section = [0..IMAGE_DIRECTORY_ENTRY_IAT]
// sRVA = 节的VirtualAddress(RVA)
// RawAddr = 节的物理地址(Phys Off), 相对于BASE的偏移
// 如果指定的节(Section)中的信息无效, 则返回False;
function PosToSectionEntry(BASE: Pointer; Section: SmallInt; var sRVA, RawAddr: DWORD): Boolean;
var
  p : pByte;
  i : Integer;
  Size : DWORD;
begin
  Result := False;
  RawAddr := 0;

  // 定位到PE头, 取导入表的VirtualAddress
  p := BASE;
  inc(p, PImageDosHeader(p)^._lfanew);
  with PImageNtHeaders(p)^ do
  begin
    Size := FileHeader.NumberOfSections;
    sRVA := OptionalHeader.DataDirectory[Section].VirtualAddress;
    if sRVA = 0 then
      Exit;
  end;

  // 定位到节表数组, 取导入表的物理地址
  inc(p, PImageNtHeaders(p)^.FileHeader.SizeOfOptionalHeader-SizeOf(TImageOptionalHeader));
  inc(p, SizeOF(TImageNtHeaders));
  for i := 0 to Size - 1 do
    with PSectionHeaderArr(p)^[i] do
      // 如果虚地址相等或者sRVA落在节的内部
      if (sRVA = VirtualAddress) or
         ((sRVA > VirtualAddress) and (sRVA <= VirtualAddress + Misc.VirtualSize)) then
      begin
        RawAddr := PointerToRawData + (sRVA - VirtualAddress);
        Result := True;
        Exit;
      end;
end;

// Offset   : 结构起点的偏移
// BaseVA   : 资源节起点的相对虚地址
// BaseAddr : 资源节在内存中的起点
function EnumResources(Offset, BaseVA, BaseAddr : DWORD; ResName : String = '') : Integer;
var
  pResStart : PImageResourceDirectory;
  pEntryArr : PResourceDirectoryEntryArr;
  pData     : PImageResourceDataEntry;
  tempSize  : Integer;
  NameOrID  : String;
  isRoot    : Boolean;
  isDir     : Boolean;
  i : integer;
begin
  Integer(pResStart) := Offset + BaseAddr;
  isRoot := Offset = 0;

  // 使用id的元素 + 使用名称的元素
  Result := pResStart^.NumberOfIdEntries + pResStart^.NumberOfNamedEntries;
  tempSize := Result;

  // 跳过目录结构
  inc(pResStart);
  pEntryArr := Pointer(pResStart);

  for i := 0 to tempSize - 1 do
    with pEntryArr^[i] do
      if isRoot then
      begin
        writeln('-----------------------------------------');
        writeln(GetResourceClass(Name.NameOffSet));
        writeln('-----------------------------------------');
        dec(Result);
        Result := Result + EnumResources(Directory.OffsetToDirectory and $7FFFFFFF, BaseVA, BaseAddr);
      end
      else
      begin
        isDir := Directory.OffsetToData and IMAGE_RESOURCE_DATA_IS_DIRECTORY <> 0;
        NameOrID := GetResourceName(Name.NameOffSet, BaseVA, BaseAddr);

        //数据目录
        if isDir then
        begin
          dec(Result);
          Result := Result + EnumResources(Directory.OffsetToDirectory and $7FFFFFFF, BaseVA, BaseAddr, NameOrID);
        end
        else
        begin
          if NameOrId = '0' then NameOrId := ResName;
          Integer(pData) := Directory.OffsetToData + BaseAddr;
          with pData^ do
          begin
            writeln(format('%-15s%-8u%-10.8x%-8u',[NameOrID, Size, OffsetToData, CodePage]));
            //writeln(GetStringFromRVA(OffsetToData, BaseVA, BaseAddr));
          end;
        end;
      end;
end;

begin
  with TMemoryStream.Create do
  begin
    if ParamCount > 0 then
      LoadFromFile(ParamStr(1))
    else
      LoadFromFile(ParamStr(0));

    // DOS 头部
    p := memory;
    writeln('DOS头部标志: $', IntToHex(PImageDosHeader(p)^.e_magic, 4), '  --> MZ');

    // PE 头部标志
    inc(p, PImageDosHeader(p)^._lfanew);
    writeln(' PE头部标志: $', IntToHex(PImageNtHeaders(p)^.Signature, 8), '  --> PE');

    // PE 头部
    with PImageNtHeaders(p)^.FileHeader do
    begin
      writeln(' PE头部的域 ==> ');
      writeln('      NumberOfSections : ', NumberOfSections);
      writeln('         TimeDateStamp : $', IntToHex(TimeDateStamp, 8));
    end;
  
    // PE 可选头部
    writeln(' 数据目录信息 ==> ');
    writeln('Size':16, 'VirtualAddress':16);
    with PImageNtHeaders(p)^.OptionalHeader do
      for i := 0 to NumberOfRvaAndSizes - 1 do
      begin
        if DataDirectory[i].VirtualAddress = 0 then continue;
        system.write('--> ':8);
        system.write(IntToHex(DataDirectory[i].Size, 8));
        writeln(IntToHex(DataDirectory[i].VirtualAddress, 8):10);
      end;

    tempSize := PImageNtHeaders(p)^.FileHeader.NumberOfSections;

    // 修正数据目录
    inc(p, PImageNtHeaders(p)^.FileHeader.SizeOfOptionalHeader-SizeOf(TImageOptionalHeader));

    // 节表
    inc(p, SizeOF(TImageNtHeaders));
    writeln('节表起始地址: $', IntToHex(Integer(p)-Integer(memory), 8));

    writeln('VirtualAddress':32);
    for i := 0 to tempSize - 1 do
      with PSectionHeaderArr(p)^[i] do
        Writeln(TSectionName(Name):13, ' --> ', IntToHex(VirtualAddress, 8));

    // 定位到资源节, 输出
    p := memory;
    PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_RESOURCE, VABase, RawAddr);
    inc(p, RawAddr);
    writeln('资源表起始地址: ', IntToHex(RawAddr, 8));
    writeln(format('%-15s%-8s%-10s%-8s',['资源','长度','RVA','CodePage']));
    Writeln('共检索到资源数: ', EnumResources(0, VABase, Integer(p)));

    // 定位到导入表, 输出
    p := memory;
    PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_IMPORT, VABase, RawAddr);
    writeln('导入表起始地址: ', IntToHex(RawAddr, 8));
    inc(p, RawAddr);
    pBASE := DWORD(p);
    while PImageImportDecriptor(p)^.Name <> 0 do
      with PImageImportDecriptor(p)^ do
      begin
        sRVA := Name;
        if Union.OriginalFirstThunk <> 0 then
          writeln(pChar(pBASE + (Name - VABase)):16, IntToHex(Union.OriginalFirstThunk, 8):10)
        else
          writeln(pChar(pBASE + (Name - VABase)):16, IntToHex(FirstThunk, 8):10);
        inc(p, SizeOf(TImageImportDecriptor));
      end;

    // 第一个导入文件的导入例程列表
    if PImageImportDecriptor(pBASE)^.Union.OriginalFirstThunk <> 0 then
      DWORD(p) := pBASE + (PImageImportDecriptor(pBASE)^.Union.OriginalFirstThunk - VABase)
    else
      DWORD(p) := pBASE + (PImageImportDecriptor(pBASE)^.FirstThunk - VABase);
    while PImageThunkData(p)^.Function_ <> 0 do
    begin
      if PImageThunkData(p)^.Ordinal and IMAGE_ORDINAL_FLAG32 <> 0 then //高位为1
        writeln(format('ord: %17.8x', [PImageThunkData(p)^.Ordinal and $7FFFFFFF]))
      else
      begin
        sRVA := PImageThunkData(p)^.AddressOfData;
        with PImageImportByName(pBASE + (sRVA - VABase))^ do
          writeln(format('name: %-16s Hint: %.4x', [String(pChar(@Name)), Hint]));
      end;

      inc(p, SizeOf(PImageThunkData));
    end;

    //导出表(仅使用名字访问)
    p := memory;
    if PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_EXPORT, VABase, RawAddr) then
    begin
      writeln('导出表起始地址: ', IntToHex(RawAddr, 8));
      inc(p, RawAddr);
      pBASE := DWORD(p);
      with PImageExportDirectory(p)^ do
      begin
        DWORD(pFunctionRVA) := pBASE + (DWORD(AddressOfFunctions) - VABase);

        DWORD(pNameRVA) := pBASE + (DWORD(AddressOfNames) - VABase);
        DWORD(pOrdinal) := pBASE + (DWORD(AddressOfNameOrdinals) - VABase);
        for i := 0 to NumberOfNames - 1 do
        begin
        writeln(format('Func: %.8x  Ord: %.4x  %S',
                       [pFunctionRVA^[pOrdinal^],
                        pOrdinal^ + Base,
                        String(pChar(pBASE + (pNameRVA^ - VABase)))]));
          inc(pNameRVA);
          inc(pOrdinal);
        end;
      end;
    end;

    //重定位表
    p := memory;
    if PosToSectionEntry(p, IMAGE_DIRECTORY_ENTRY_BASERELOC, VABase, RawAddr) then
    begin
      writeln('重定位表起始地址: ', IntToHex(RawAddr, 8));
      inc(p, RawAddr);
      pBASE := DWORD(p);
      while PImageBaseRelocation(p)^.VirtualAddress <> 0 do
        with PImageBaseRelocation(p)^ do
        begin
          if pBASE <> DWORD(p) then
            writeln('Next Relocation Table Section...');
          tempSize := (SizeOfBlock - SizeOf(TImageBaseRelocation)) div SizeOf(WORD);
          DWORD(pRelocItem) := DWORD(p) + SizeOf(TImageBaseRelocation);
          for i := 0 to tempSize - 1 do
          begin
            Writeln(format('RVA: %.8x, Type: %.4x', [VirtualAddress + pRelocItem^ AND $0FFF, pRelocItem^ SHR 12]));
            inc(pRelocItem);
          end;

          p := Pointer(pRelocItem);
          //DWORD(p) := DWORD(p) + SizeOfBlock;
        end;
    end;

    free;
  end;

//readln;
end.

⌨️ 快捷键说明

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