3

Windows 10 コンピューターの NtDll エクスポート テーブルを調べていたところ、、、、などの標準 C ランタイム関数がエクスポートされていることがわかりましmemcpyた。sprintfstrlen

LoadLibraryと を介して実行時に動的に呼び出すことができるということGetProcAddressですか? これはすべての Windows バージョンに当てはまりますか?

もしそうなら、(NtDll の CRT 関数を使用するだけで) C ランタイム ライブラリを完全に削除できるので、プログラムを小さくできますか?

4

3 に答える 3

8

NtDll によってエクスポートされたこれらの文書化されていない関数を呼び出す理由はまったくありません。Windows は、すべての重要な C ランタイム関数を、標準システム ライブラリ (Kernel32) から文書化されたラッパーとしてエクスポートします。C ランタイム ライブラリ*に絶対にリンクできない場合は、これらの関数を呼び出す必要があります。メモリについては、基本的なand (またはおそらくand ) 、、、、などがあります。文字列操作については、重要な CRT 関数がすべてそこにあり、:、、、、などのプレフィックスが付いています。兄弟HeapAllocHeapFreeVirtualAllocVirtualFreeZeroMemoryFillMemoryMoveMemoryCopyMemoryllstrlenlstrcatlstrcpylstrcmpwsprintfwvsprintf)、接頭辞が異なるだけでなく、浮動小数点値もサポートしていません (これらの関数が最初にエクスポートされて文書化された初期の頃、Windows 自体には浮動小数点コードがありませんでした)。他にもさまざまなヘルパー関数があります。IsCharLowerCharLowerCharLowerBuffなどの CRT の機能を複製します。

これは、 C ランタイム関数の Win32 Equivalents の一部を文書化した古いナレッジ ベース記事です。CRT の機能を再実装する場合におそらく必要となる関連する Win32 関数が他にもある可能性がありますが、これらは直接のドロップイン置換です。

これらの一部は、オペレーティング システムのインフラストラクチャで絶対に必要であり、CRT 実装によって内部的に呼び出されます。このカテゴリには、オペレーティング システムの責任であるHeapAllocや などのものが含まれます。HeapFreeランタイム ライブラリはそれらをラップするだけで、OS レベルの詳細に加えて、優れた標準 C インターフェイスとその他の優れた機能を提供します。文字列操作関数のようなその他のものは、CRT の内部 Windows バージョンのラッパーをエクスポートしただけです (ただし、CRT の非常に古いバージョンであり、歴史のある時点で修正され、パッチが適用された可能性のある主要なセキュリティ ホールを除いて)長年にわたって)。さらに他のものは、ほぼ完全に不必要であるか、またはそう思われますZeroMemoryMoveMemory、実際にはエクスポートされているため、従来の Visual Basic (VB 6) のような C ランタイム ライブラリがない環境から使用できます。

また、「単純な」C ランタイム ライブラリ関数の多くが、Microsoft (および他のベンダー) のコンパイラによって組み込み関数として実装されており、特別な処理が行われていることも興味深い点です。これは、高度に最適化できることを意味します。基本的に、関連するオブジェクト コードはアプリケーションのバイナリに直接インラインで出力されるため、コストがかかる可能性のある関数呼び出しが不要になります。常に呼び出されるなどのインライン コードをコンパイラが生成できるようstrlenにすると、エクスポートされた Windows API の 1 つに関数呼び出しのコストを支払うよりも、ほぼ間違いなくパフォーマンスが向上します。コンパイラが「インライン化」する方法はありませんlstrlen; 他の関数と同じように呼び出されます。これにより、速度とサイズの間の古典的なトレードオフに戻ります。小さいバイナリの方が高速な場合もありますが、そうでない場合もあります。CRT をリンクする必要がない場合、インライン実装ではなく関数呼び出しを使用するため、より小さなバイナリが生成されますが、一般的なケースではおそらく高速なコードは生成されません。

*ただし、さまざまな理由から、コンパイラにバンドルされている C ランタイム ライブラリにリンクする必要があります。その理由の 1 つは、ランタイム ライブラリの更新バージョンを介してオペレーティング システムのすべてのバージョンに配布できるセキュリティ更新プログラムです。 . あなたは本当に正当な理由を持っている必要があります世界最小の実行可能ファイルをビルドしようとしている場合など、CRT を使用しないでください。これらの機能を利用できないことは、最初のハードルにすぎません。CRT は、プロセスを起動して実行する、標準の C または C++ 環境を設定する、コマンド ライン引数を解析する、静的初期化子を実行する、コンストラクターを実装するなど、通常は考える必要のない多くのことを処理します。デストラクタ (C++ を作成している場合)、構造化された例外処理 (C++ 例外にも使用される SEH) のサポートなど。CRT に依存せずにコンパイルする単純な C アプリを入手しましたが、かなりの手間がかかりました。リモートで深刻なものにはお勧めしません。マシュー・ウィルソンはずっと前に記事を書きましたVisual C++ ランタイム ライブラリの回避。Visual C++ 6 開発環境に焦点を当てているため、ほとんど時代遅れですが、全体像の多くはまだ関連しています。Matt Pietrek も、かなり前に Microsoft Journal にこれに関する記事を書いています。タイトルは「ボンネットの下: LIBCTINY.LIB を使用して EXE と DLL のサイズを縮小する」でした。コピーは引き続きMSDNで見つけることができます。また、Microsoft の再編成中にアクセスできなくなった場合は、Wayback Machineで見つけることができます。(リンクを掘り下げてくれたIInspectableGertjan Brouwerに敬意を表します!)

アプリケーションと一緒に C ランタイム ライブラリ DLL を配布する必要があるだけの場合は、CRTに静的にリンクすることを検討できます。これにより、コードが実行可能ファイルに埋め込まれ、個別の DLL が不要になります。繰り返しますが、これにより実行可能ファイルが肥大化しますが、インストーラーや ZIP ファイルさえも必要とせずにデプロイが簡単になります。これの大きな注意点は、当然のことながら、CRT DLL に対する増分セキュリティ更新プログラムの恩恵を受けられないことです。これらの修正を取得するには、アプリケーションを再コンパイルして再配布する必要があります。他に依存関係のないおもちゃのアプリの場合、私はしばしば静的リンクを選択します。それ以外の場合は、引き続き動的リンクが推奨されるシナリオです。

于 2016-08-16T16:51:29.853 に答える
0

LoadLibrary と GetProcAddress を介して実行時に動的に呼び出すことができるということですか?

はい。さらに- ntdll への静的バインディングに ntdll.lib (または ntdllp.lib) を使用しないのはなぜですか? この後、GetProcAddressなしでこの関数を直接呼び出すことができます

これはすべての Windows バージョンに当てはまりますか?

nt4からwin10まで、ntdllには多くのCランタイム関数が存在しますが、設定が異なります。通常、バージョンごとに大きくなります。しかし、それほど機能的でないものは msvcrt.dll と比較してください。たとえばprintf、ntdll は浮動小数点形式をサポートしていませんが、一般的に機能は同じです。

(NtDll の CRT 関数を使用するだけで) C ランタイム ライブラリを完全に削除できるので、プログラムを小さくできますか?

はい、これは 100% 可能です。

于 2016-08-18T22:34:44.073 に答える