exeファイルのimport sectionのアドレス取得したい

解決


やまだ  2010-04-20 10:48:15  No: 38306

delphi で  exeファイルのimport sectionを取得したいですが
どうやるのでしょうか?

APIがあるみたいですが自力でやりたいです。
http://bbs.wankuma.com/index.cgi?mode=al2&namber=46936&KLOG=79を
みましたが「VirtualAddress - PointerToRawData を データディクショナリの RVA から引いてやれば、ファイル上での位置がわかります」の部分がよくわかりません。

下記途中までのソース

program peExe;

{$APPTYPE CONSOLE}

uses
SysUtils,Classes,windows;
type
IMAGE_DOS_HEADER = record // DOS .EXE header
  e_magic:word; // Magic number
  e_cblp:word; // Bytes on last page of file
  e_cp:word; // Pages in file
  e_crlc:word; // Relocations
  e_cparhdr:word; // Size of header in paragraphs
  e_minalloc:word; // Minimum extra paragraphs needed
  e_maxalloc:word; // Maximum extra paragraphs needed
  e_ss:word; // Initial (relative) SS value
  e_sp:word; // Initial SP value
  e_csum:word; // Checksum
  e_ip:word; // Initial IP value
  e_cs:word; // Initial (relative) CS value
  e_lfarlc:word; // File address of relocation table
  e_ovno:word; // Overlay number
  e_res:array [0..3] of word; // Reserved words
  e_oemid:word; // OEM identifier (for e_oeminfo)
  e_oeminfo:word; // OEM information; e_oemid specific
  e_res2:array[0..9] of word; // Reserved words
  e_lfanew:dword; // File address of new exe header
end;

IMAGE_FILE_HEADER = record
  Machine:WORD;
  NumberOfSections:WORD;
  TimeDateStamp:DWORD;
  PointerToSymbolTable:DWORD;
  NumberOfSymbols:DWORD;
  SizeOfOptionalHeader:WORD;
  Characteristics:WORD;
end;

IMAGE_DATA_DIRECTORY = record
  RVA:DWORD;
  Size:DWORD;
end;
IMAGE_OPTIONAL_HEADER32 = record
//
// Standard fields.
//

  Magic:word;
  MajorLinkerVersion:BYTE;
  MinorLinkerVersion:BYTE;
  SizeOfCode:DWORD;
  SizeOfInitializedData:DWORD;
  SizeOfUninitializedData:DWORD;
  AddressOfEntryPoint:DWORD;
  BaseOfCode:DWORD;
  BaseOfData:DWORD;

//
// NT additional fields.
//

  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 ;
  DataDirectory:array [0..15] of IMAGE_DATA_DIRECTORY;
end;

IMAGE_NT_HEADERS = record
  Signature:DWORD;
  FileHeader:IMAGE_FILE_HEADER;
  OptionalHeader:IMAGE_OPTIONAL_HEADER32;
end;

IMAGE_SECTION_HEADER = record
    Name:array[0..7] of BYTE;
    Misc:DWORD;
    VirtualAddress:DWORD;
    SizeOfRawData:DWORD;
    PointerToRawData:DWORD;
    PointerToRelocations:DWORD;
    PointerToLinenumbers:DWORD;
    NumberOfRelocations:WORD;
    NumberOfLinenumbers:WORD;
    Characteristics:DWORD;

end;

IMAGE_IMPORT_DESCRIPTOR = record
    OriginalFirstThunk:DWORD;
        // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    TimeDateStamp:DWORD;
    ForwarderChain:DWORD;
        // -1 if no forwarders
    Name:DWORD;
    FirstThunk:DWORD;
        // RVA to IAT (if bound this IAT has actual addresses)
end;

function toLittleE(val:word):word;overload;
begin

  result := val shl 8;
  result := result or (val shr 8);
end;

function toLittleE(val:dword):dword;overload;
begin

  result := val shl 24;
  result := result or ( ($0000FF00 and val) shl 8);
  result := result or ( ($00FF0000 and val) shr 8);
  result := result or ( ($FF000000 and val) shr 24);
//result := result or (val shr 8);
end;

const
  dosfmt = ' Magic number=%s'+#13#10
  +' File address of new exe header=%s';
  ntfmt = ' Signature=%s';
  filefmt =' Machine=%s'+#13#10
          +' NumberOfSections=%s';
  dirfmt ='no=%2d'
          +' rva=%s'+#13#10
          +' size=%s';
  optfmt = ' AddressOfEntryPoint=%s'+#13#10
  +' BaseOfCode=%s'+#13#10
  +' BaseOfData=%s'+#13#10
  +' ImageBase=%s'+#13#10
  +' SectionAlignment=%s'+#13#10
  +' SizeOfStackReserve=%s'+#13#10
  +' SizeOfStackCommit=%s'+#13#10
  +' SizeOfHeapReserve=%s'+#13#10
  +' SizeOfHeapCommit=%s'+#13#10
  +' NumberOfRvaAndSizes=%s'+#13#10;

  scfmt = ' Name:(%s)'+#13#10
         +' VirtualSize:%s'+#13#10
         +' SizeOfRawData:%s'+#13#10
         +' PointerToRawData:%s'+#13#10
         +' Characteristics:%s';
var
  binFile:TFileStream;
  dosHeader:IMAGE_DOS_HEADER;
  ntHeader:IMAGE_NT_HEADERS;
  scHeader:IMAGE_SECTION_HEADER;
  ipHeader:IMAGE_IMPORT_DESCRIPTOR;
  Buf: array[0..SizeOf(IMAGE_DOS_HEADER) * 2] of Char;
  i,j:Integer;
  temp:String;
  importAddr:DWORD;
begin
{ TODO -oUser -cConsole Main : この下にコードを記述してください }
  Writeln(paramStr(1));
  binFile := TFileStream.Create(ParamStr(1),fmOpenRead);
  binFile.Read(dosHeader,sizeof(IMAGE_DOS_HEADER));
  Writeln('[IMAGE_DOS_HEADER]');
  Writeln(format(dosfmt,
  [IntToHex(dosHeader.e_magic,4)
  ,IntToHex(dosHeader.e_lfanew,2)]));
  binFile.Seek($100,soFromBeginning);
  binFile.Read(ntHeader,sizeof(IMAGE_NT_HEADERS));
  Writeln('[IMAGE_NT_HEADERS]');
  Writeln(format(ntfmt,[IntToHex(ntHeader.Signature,8)]));
  Writeln('[IMAGE_FILE_HEADER]');
  Writeln(format(filefmt,[IntToHex(ntHeader.FileHeader.Machine,4),IntToHex(ntHeader.FileHeader.NumberOfSections,4)]));

  Writeln('[IMAGE_OPTIONAL_HEADER32]');
  Writeln(format(optfmt,[IntToHex(ntHeader.OptionalHeader.AddressOfEntryPoint,8)
  ,IntToHex(ntHeader.OptionalHeader.BaseOfCode,8)
  ,IntToHex(ntHeader.OptionalHeader.BaseOfData,8)
  ,IntToHex(ntHeader.OptionalHeader.ImageBase,8)
  ,IntToHex(ntHeader.OptionalHeader.SectionAlignment,8)
  ,IntToHex(ntHeader.OptionalHeader.SizeOfStackReserve,8)
  ,IntToHex(ntHeader.OptionalHeader.SizeOfStackCommit,8)
  ,IntToHex(ntHeader.OptionalHeader.SizeOfHeapReserve,8)
  ,IntToHex(ntHeader.OptionalHeader.SizeOfHeapCommit,8)
  ,IntToHex(ntHeader.OptionalHeader.NumberOfRvaAndSizes,8)]));

  Writeln('[IMAGE_DATA_DIRECTORY]');
  for i:=0 to ntHeader.OptionalHeader.NumberOfRvaAndSizes - 1 do begin
    writeln(format(dirfmt,[i
                ,IntToHex(ntHeader.OptionalHeader.DataDirectory[i].RVA,8)
                ,IntToHex(ntHeader.OptionalHeader.DataDirectory[i].SIZE,8)]));
  end;

  Writeln('[IMAGE_SECTION_HEADER]');
  for i := 0 to ntHeader.FileHeader.NumberOfSections - 1 do begin
    binFile.Read(scHeader,sizeof(IMAGE_SECTION_HEADER));
    temp := '';
    for j := 0 to 7 do temp := temp + char(scHeader.Name[j]);
    writeln(format(scfmt,[temp
    ,IntToHex(scHeader.Misc,8)
    ,IntToHex(scHeader.SizeOfRawData,8)
    ,IntToHex(scHeader.PointerToRawData,8)
    ,IntToHex(scHeader.Characteristics,8)]));
    if temp = '.idata'+#0#0 then importAddr := scHeader.PointerToRawData;
  end;
  Writeln('[インポートセクション]');  
  binFile.Seek(importAddr,soFromBeginning);
  binFile.Read(ipHeader,sizeof(IMAGE_IMPORT_DESCRIPTOR));
  binFile.Read(temp,$36);               
 /// readln;

end.


DEKO  2010-04-20 12:14:08  No: 38307

こんにちは。

リンク先には
> あとは前回書いた通り、
>    IMAGE_DATA_DIRECTORY::VirtualAddress - ( IMAGE_SECTION_HEADER::VirtualAddress - IMAGE_SECTION_HEADER::PointerToRawData )
> が、ファイル上でのインポートデスクリプタ(IMAGE_IMPORT_DESCRIPTOR)の位置になります。

とありますから、

IMAGE_DATA_DIRECTORY.RVA - (IMAGE_SECTION_HEADER.VirtualAddress - IMAGE_SECTION_HEADER.PointerToRawData)
となるのではないでしょうか。

なお PE ヘッダ等の構造体は、あらかた Windows.pas にて定義されています。
RTL の定義で書きなおすと、

IMAGE_DATA_DIRECTORY.VirtualAddress - (IMAGE_SECTION_HEADER.VirtualAddress - IMAGE_SECTION_HEADER.PointerToRawData)
となると思います。


やまだ  2010-04-21 00:03:30  No: 38308

ご返信ありがとうございました。
お陰様でインポートデスクリプタの取得方法は、分かりましたので
少しテストしてみます。

なので解決といたします。
ありがとうございました。


やまだ  2010-04-21 08:02:24  No: 38309

ぽちっとな


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加