エクスポートテーブルのPE PEの知識のレビュー

ディアンプロフィール

 PEを説明する前に、テーブルをエクスポートします。私たちは理解したい。PE実行可能プログラムを。その中の一つのファイルで構成されています。

回答:などないPEファイルの多くによって.DLLファイルはPE PEファイルで実行され、我々は、システム上のDLL DLLはKerner32.dllのuser32.dllのある頼る必要がある場合には、これらは、PEファイルです.....

エクスポートテーブルにはどのようなものです:

    エクスポートテーブルは、現在のPEファイルが例と他の人にこれらの機能を提供している:.. PEファイルは、テーブルのエクスポートされたレストランのメニューに相当します。

エクスポートソリューションブラインドテーブル:

    一部の人々はありません一般的なEXE。エグゼファイルも他の人が使用するための関数をエクスポートすることができます。基本的にPEファイルやDLL。かどうかのexeファイル。exeファイルの実行可能ファイルは、テーブルをエクスポートしません。そして、DLLエクスポートテーブルがあること。これは間違っていると思いますが、ではありません持っていない。区別に注意してください。

説明するために、2つのディアンエクスポートテーブル

    エクスポートテーブルを説明する前に。私たちは、どこのテーブルをエクスポートするかを決定します。

拡張ヘッダを説明するための時間では。。私たちは、このデータディレクトリと呼びます。構造体の配列がある16人のメンバーが。

typedefは構造体_IMAGE_DATA_DIRECTORY { 
    ;仮想アドレスDWORD VirtualAddress 
    ; DWORDサイズサイズ
IMAGE_DATA_DIRECTORYの、} * PIMAGE_DATA_DIRECTORY。

インポートテーブルのエクスポートテーブルのデータディレクトリに格納されています。

この構造は、どこのエクスポートテーブルに格納されている。そして、どのようにテーブルをエクスポートすることです。

 データが別のテーブルに保存されている各ディレクトリ

最初の例では、エクスポートテーブルのエクスポートテーブルは、仮想アドレスとサイズを記録しています。

次のように:

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0    // エクスポートディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_IMPORT 1    // インポートディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2    // リソースディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3    // 例外ディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_SECURITY 4    // セキュリティディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5    // ベースリロケーションテーブル
#定義 IMAGE_DIRECTORY_ENTRY_DEBUG 6    // デバッグディレクトリを
//       IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7    // (X86使用)
の#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7    // アーキテクチャ固有のデータ
の#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8    // RVA GP用の
の#define IMAGE_DIRECTORY_ENTRY_TLS 9    // TLSディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10    // ロード構成ディレクトリ
の#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11    / / ヘッダーでインポートディレクトリバウンド
の#define IMAGE_DIRECTORY_ENTRY_IAT 12    //インポートアドレステーブル
の#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13    // 遅延ロードインポート記述子
の#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14    // COMランタイム記述子

構造体は、レコードのエクスポートテーブルRVAですので。だから我々はPEファイルを表示するFOAを変換する必要があります。

RVAは、そのセクションを決定した。RVA-違いオフセット部の.VirtuallAddressを==

+ FOA ==違いオフセット部.PointerToRawData

 

テーブルをエクスポートするように配置されている場合、フロントは述べています。本当のエクスポートテーブルの構造を配置した後。

typedefは構造体_IMAGE_EXPORT_DIRECTORY { 
    ; DWORD特性     // 赤い重要でないなし 
    ; DWORD TimeDateStamp       // タイムスタンプは、DLLに秒単位で時間までの時間をコンパイル....それがコンパイルされたものを時間を知ることができ
    WORDのMajorVersionを、
    WORD MinorVersionの。
    名前のDWORD;           // ファイルにFOAが自分を計算することができ見たい場合はRVAのストレージには影響を与えませんDLL補助情報の変更の名前でポイントエクスポートテーブルに「ファイル名の文字列、... 
    DWORDベース;           // 輸出シリアル番号の関数開始 
    DWORDのNumberOfFunctionsを;      // すべてのエクスポートされた関数の数 
    DWORD NumberOfNames;          // エクスポートされた関数の名前の数は 
    AddressOfFunctionsをDWORD;      // 関数アドレステーブルをエクスポートアドレスRVAは、関数アドレスであります  
    AddressOfNames DWORD;          // RVA関数を派生テーブルのテーブル名の関数名で 
    DWORDのAddressOfNameOrdinals;   // 導出機能IDテーブルIDテーブル関数は、RVAである 
} IMAGE_EXPORT_DIRECTORY、* PIMAGE_EXPORT_DIRECTORY。

エクスポートテーブルのサイズはの0x28バイトです。それは2年半ラインです。

一つの重要なメンバーは赤でマークされている。最も重要なことは、最後の三つのメンバー。三サブテーブルにテーブルをエクスポートすることです。

すべてのRVA

PS :.会員データディレクトリのサイズは、エクスポートテーブルに保存されているだけでなく、コンパイラが完了した後の計算の値には影響を与えない子テーブルのエクスポートテーブルのサイズのすべてのメンバーます。..

 

水とエクスポートテーブルのメンバーが解決します

typedefは構造体_IMAGE_EXPORT_DIRECTORY { 
    ; DWORD特性     // 赤い重要でないなし 
    ; DWORD TimeDateStamp       // タイムスタンプは、DLLに秒単位で時間までの時間をコンパイル....それがコンパイルされたものを時間を知ることができ
    WORDのMajorVersionを、
    WORD MinorVersionの。
    名前のDWORD;           // ファイルにFOAが自分を計算することができ見たい場合はRVAのストレージには影響を与えませんDLL補助情報の変更の名前でポイントエクスポートテーブルに「ファイル名の文字列、... 
    DWORDベース;           // 輸出シリアル番号の関数開始 
    DWORDのNumberOfFunctionsを;      // すべてのエクスポートされた関数の数 
    DWORD NumberOfNames;          // エクスポートされた関数の名前の数は 
    AddressOfFunctionsをDWORD;      // 関数アドレステーブルをエクスポートアドレスRVAは、関数アドレスであります  
    AddressOfNames DWORD;          // RVA関数を派生テーブルのテーブル名の関数名で 
    DWORDのAddressOfNameOrdinals;   // 導出機能IDテーブルIDテーブル関数は、RVAである 
} IMAGE_EXPORT_DIRECTORY、* PIMAGE_EXPORT_DIRECTORY。

エクスポートテーブルを解析する。必要なのは、DLLです。ここで私は、システムDLLのkerner32.dll解像度のコピーを見てください。

最初のステップは、エクスポートテーブルのエクスポートテーブルを解析見つけることである。FOA得られる。それは、ファイル内の位置です。

エクスポートされたデータディレクトリテーブルRVAを見ます

データディレクトリをエクスポート表RVAの== 0x90380サイズで結果== D4DC

ビューは、そのセクションに所属する。FOAが得られ

 

セクションの仮想アドレス== 0x80000セクションを描かれた。セクション== 0x65000のオフセット.Rdataファイル

 

FOA = 0x90380 - 0x80000 + 0x65000 == 0x75380

したがって、エクスポートファイルオフセットテーブル構造のためのPEファイル。0x75380です。

 

 

1.Nameのメンバーが解決します

 まず、エクスポートテーブルの重要なメンバーを解決

輸出ポジションテーブルの行ストレージ0x9416AこれはRVAある時Nmaeは:.ので、ここで直接計算FOA FOA ==の7916Aを変換したいです...

 

このメンバーは、あなたのDLLの名前を保存するために表示されています。

2.Base 解決のメンバー。  シリアル番号を開始する派生関数を

 開始位置エクスポート機能番号。エクスポートDLL関数。あなたは、番号を与える場合。その後、この番号から始まります。 

3.NumberOfFunctions NumberOfNmaes  輸出の合計数の関数をそして、数の名前の関数をエクスポート

二つの部材は非常に簡単です。すべてのこと、輸出の数の関数である。名前は数が導出される。DLLは、シリアル番号で求めることができます。

 

すべての機能は、62Dの機能を輸出している。62Dは、輸出への関数名です。あなたは、シリアル番号に基づいてエクスポートする必要があります。すべての機能をエクスポートする関数名の数が異なるの番号でエクスポートされますので。

そして、式を算出することができる。エクスポート機能はどのように多くのではありませんがあります。

すべてのエクスポート関数の数 - 派生名の数の数に==差が数字をエクスポートまたはエクスポートされません。

4.1 関数アドレステーブル

  フロントは非常に簡単です。次の表は、子供です。

 

三サブテーブルは、私たちがFOA変換について行われてきた直接RVAです。

関数のアドレステーブルFOA == 0x753A8

関数名テーブルFOA == 0x76c5c

関数リファレンス表FOAの== 0x78510

  アドレステーブル関数:派生したすべての機能の数のオフセットアドレス記憶されたオフセット関数の関数アドレステーブルポイント。

全ての機能は二つの、例えば、誘導される。誰が4つのバイトでない関数アドレステーブル2があるので。RVAオフセット関数のアドレスが格納されます。

 

関数アドレステーブルは4バイト。サイズ機能エクスポートされた関数内のすべてのバイトの合計数。例えばRVAは、最初のアドレスオフセット+ IMAGEBASE 0x0162A0関数は、関数のアドレスオフセット。

 

例えば、自分のコンピュータ上Kerner32.dllは、ファイルオフセットで私たちの機能で見7636万にIMAGEBASEをロードし、エクスポート機能が0x763762A0に対処し0x162A0合計することによって得られます

PS :.私たちはFOA変換されたファイルにエクスポートされた表を表示するので、メモリに見れば非常に簡単です。

RVA + IMAGEBASE位置決めデータのエクスポートテーブル位置ディレクトリ。

定義されたRVAエクスポートテーブルの構造は、他のテーブルの位置に来ることができ+ IMAGEBASEを相殺した。我々は、変換されません。

还需要注意的就是,如果你按照序号导出. 1 3 4 5导出了4个函数. 在导入表中我们的函数地址表中的地址会有5个.原因就是.序号会给我们用0填充. 1 2 3 4 5 虽然第二项并没有.但是也会给我们导出.

如果函数地址我们已经知道了.我们要怎么只有函数地址的情况下.确定是哪个函数?

4.2 函数名称表

  函数名称表也是存储的名称RVA. 4个字节存储一个. 存储的大小 跟导出表的以函数名字导出个数 这个成员来决定的.

以名称导出函数的个数 例如为10 .那么函数名称表就可以存储10个RVA. 每一个为4个字节.

里面的RVA指向了当前导出函数的函数名称.

例如上面已经算出 函数地址表的FOA位置

函数名称表 FOA == 0x76c5c

那么我们去函数名称表中查看.

表中存储的都是RVA. 如果在内存中.我们直接RVA + 当前PE的ImageBase就可以看到函数导出的名称了.不过我们现在算一下.

FOA = 0x941D6  - 0x80000 + 0x65000 = 0x791D6

我们表中的第一项的FOA位置为0x791d6 在文件中就保存这导出函数的名称

例如下图文件偏移处:

注意: 函数名称表保存的并不是函数名称.而是指向函数名称的RVA偏移. 还有RVA偏移是按照字母排序的.并不是按照你导出的时候函数的顺序进行排序的.

例如:

  EXPORT

    SUB

    ADD

    MUL

导出三个函数.那么第一项就为 ADD.因为按照字母排序.A在前边.后面依次类推. 所以我们上面看到的函数名称 ACquireSRW 这个函数名称.并不是Kerner32.dll第一个导出的函数.

4.3函数序号表

  我们DLL导出函数的时候.会有序号进行导出.但是并不是说.如果按照名字导出名称表中有.序号表中就没有.

序号表的个数跟函数名称表个数是一样的.都依赖成员 导出表.函数名称导出表个数 这个成员来决定的.

序号表是给名称表的使用的.  序号表占两个字节.存储序号.

函数序号表 FOA == 0x78510

 

0300  0400 0500 序号.两个字节进行存储的

常用函数 GetProcAddress(模块,名字或者序号)

我们这个函数就是遍历PE文件中导出表进行返回的. 那么他是如何实现的.如何通过名字查找函数地址. 或者如何通过序号进行查找函数地址的?

首先我们要分成三张表,函数地址表中序号开始的位置是导出表成员Base指定的.假设为0开始.

函数地址表                                          序号表                            函数名称表

0  0x1010  sub                          0        0x0100                         0  Add

1      0x2020  Add                           1       0x0000                          1  Sub

2  0x3030  Div                            2     0x0200                            2  DiV

首先GetProcAddress 如果按照名称查找的话.会先去遍历函数名称表.  比如我们要获取Sub的地址.  遍历函数名称表的时候.找到了Sub.  并获取当前Sub的索引.  sub是在第二项中.所以索引为1 (从0开始)

然后拿着这个索引.去序号表中进行查找对比.   在序号表中查到了.对比成功.序号表中第2项的值跟这个索引一样的.所以就拿序号表的序号. 去函数地址表中获取函数地址.

序号为0x0000. 那么他就在函数地址表中.找到了第0项. 当函数地址进行返回.  (并不是直接返回,加上了当前DLL模块的ImageBase才返回的,所以为什么需要DLL模块地址) 

所以上面就是GetProcAddress的名字查找的实现流程

 

如果是序号来查找的话.比如我们寻找 14序号. 他会先根据导出表中Base成员属性.将表的起始位置进行一次定义.

例如上面.我们找的14序号并不存在. 但是他会先看看Base起始位置是多少. 假设为13. 那么我们函数地址表中 0索引 相当于 13  1索引相当于 14  2索引相当于15了.依次类推.

这样我们虽然说寻找14. 但是根据Base起始位置的指定.那么也会寻找到我们的函数地址.

 

总结来说 :

    1.遍历函数名称表 得出索引

    2.当前索引.去序号表中查找.如果有.则取出当前序号表的序号.当做函数地址表的下标

    3.得出下标. 返回函数地址 (RVA +IMAGEbase)

 

おすすめ

転載: www.cnblogs.com/gd-luojialin/p/11306189.html