2017-05-31 8 views
1

こんにちは私はMacTのインポートリコンストラクタのようにPythonスクリプトでインポートテーブルビルダを作ろうとしています。転送されたAPIをPEのIATからどのように解決できますか?

しかし、転送されたAPIから元のAPI情報を取得する方法を見つけるのは難しいです。

たとえば、IATから "ntdll!RtlDecodePointer"を取得しましたが、 "kernel32!DecodePointer"から転送されました。これを見つけるためのアイデアはありません。

ロードされた各モジュールのForwarderChainをインポートディレクトリで検索する必要がありますか?

答えて

0

いいえ、ForwarderChain in Import directoryとは無関係です。

ローダーはいくつかPEインポートからkernel32.DecodePointerを解決する - それは、いくつかのアドレスにkernel32.dllのIMAGE_EXPORT_DIRECTORYの内側を指していることを確認 - これはとても転送輸出と呼ばれています。この場合、ローダはないコードに、しかしフォームsomedll.somefunctionまたはフォームsomedll.#someordinal中で文字列からkernel32.DecodePointerポイントは、結果ローダーがロードsomedllを試してみて、名前でsomefunctionを探しているかsomeordinal用としてあることを理解します序文でこの検索はどのように表示できますか(また、前方のエクスポートがあった場合)再帰的です。私たちは最終的に機能アドレスを持っていないときに停止しましたIMAGE_EXPORT_DIRECTORY - このアドレスはに格納されますか、IATに格納されますか、プロセスが失敗します。ここdeliminator

ノート(DLL機能間名前 - ない!しかし.)興味深い質問 - 自分の名前で.を含むsomedll場合も何 - my.x64.dllを言います。このような窓間違ったプロセス名の古いバージョン(my.x64.dll.somefunc)それはstrchrで文字列の最初の.を検索するために - そうx64.dll.somefuncmyでDLLを検索し、失敗します。しかし、これは固定ローダーの使用strrchrです - 彼は最後に.をstringで検索します。

結果として毎年我々は拡張子を持つ完全なDLL名を指定することはできません -

#pragma comment(linker, "/export:fn=kernel32.dll.DecodePointer"); 
GetProcAddress((HMODULE)&__ImageBase, "fn"); 

はXP上で言って失敗します。しかし、現在win10が正確にwin8.1(必要性をチェックする)かもしれません。これは正しく、動作します。dll.DecodePointerkernel32、win32はDecodePointerkernel32.dllで検索します。ここからも、早期にモジュールにエクスポートすることはできませんが、.dllの拡張子はありません。そのような制限はありません。コールLoadLibrary("my")そのとき - - 実際に開かれ、"my.DLL"をロードされますが、"my."または"my.x64"サフィックス.DLLのために(名前で.文字を付加しないであろう、それは.を含有しない場合(デフォルトではローダは、ロードされたライブラリ名に.DLL接尾辞をに追加します))

もしそうなら、あなたの具体的な例に戻る - IMAGE_EXPORT_DIRECTORYのkernel32.dllの内部に何かをkernel32.DecodePointerポイント。 NTDLL.RtlDecodePointer - - ローダはこのアドレスによって文字列を読む(サフィックスは名前であるため全く.を添加していない)>NTDLL.DLLRtlDecodePointerの検索 - - .を見つけ、最終的にNTDLLをロードするために、この文字列にstrrchr(またはstrchr旧バージョン)を呼び出すアドレスを発見し、それ内部ではないIMAGE_EXPORT_DIRECTORYntdll.dll - これはコードアドレスです。ここではプロセスが停止し、RtlDecodePointerのアドレスが最初に格納されます。PEIAT

あなた自身の側からは、ローダーステップを繰り返す必要があります。現代のOSには1つの問題が存在します。多くの文字列はAPI-MS-* dllの名前で始まります。これは実際のDLLではありませんが、The API Set Schema - 文書化されていない変更可能な方法、ローダーがこの名前を解決する方法

+0

ありがとうございました。私は手術の原則についてもっと学ぶ必要があると思う: ' – Vanz

0

モジュールのエクスポートテーブルを解析中にFowarder文字列を正規関数アドレスと区別できるように思えます。

もっと簡単な方法があるので、Forwarder文字列を知る前にこのForwarder文字列を解析することはお勧めしません。トリックは、エクスポートされた関数のアドレスがエクスポートセクションのメモリ範囲内にあるかどうかをチェックすることです。これは、PE/COFF仕様の「エクスポートアドレステーブル」セクションに記載されている公式の方法です。

申し訳ありませんが、下のサンプルコードはPythonではなくC言語で書かれていますが、それでもあなたには分かります。また、以下のチェックはPE32とPE64の画像にも適用されます。

エクスポートテーブルを解析するときに、IMAGE_DATA_DIRECTORYエクスポートのセクションへのポインタが既にあります。そこからIMAGE_EXPORT_DIRECTORYへのポインタを取得します。例えば。

IMAGE_DATA_DIRECTORY* pExportEntry = pOptHeader->DataDirectory->arDataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT; 
... 
//code to convert pExportEntry->VirtualAddress into file offset and store in dwExportTableFileOffset 
... 
IMAGE_EXPORT_DIRECTORY* pExportTable = (IMAGE_EXPORT_DIRECTORY*)(ImageFileBase + dwExportTableFileOffset); 

あなたはpExportTable-> AddressOfFunctionsから関数の配列ポインタを取得したと仮定すると、以下の次のチェックは関係なく、関数が名前やoridinalによってエクスポートされているかどうかの動作します。ファンクション#iの関数アドレス(下のarFuncs [i]で示される)がエクスポートセクション(すでに解析中)にある場合、アドレスは<MODULE>という形式のフォワーダ文字列を指しています。 <ExportName>、それ以外の場合は通常の機能です。

if (arFuncs[i] >= pExportEntry->VirtualAddress && arFuncs[i] < pExportEntry->VirtualAddress+pExportEntry->Size) 
{ 
    //function address is RVA to Forwarder String; e.g. NTDLL.RtlDecodePointer 
} 
else 
{ 
    //function address is RVA to actual code within current module 
} 
+0

ありがとうございました。あなたの例はとても役に立ちます! – Vanz

関連する問題