Windows 2000で動作する必要のあるアプリケーションがあります。VisualStudio 2010も使用したいと思います(主にauto
キーワードの定義が変更されたため)。ただし、古いOSでアプリを操作できるようにする必要があるため、私は少し困っています。
Visual Studio 2010のランタイムライブラリは、Windowsで導入されたEncodePointer / DecodePointer
APIに依存していますXP SP2。
代替ランタイムライブラリを使用できる場合、このブレークコードはstd::regex
などのVS2010で追加されたC++ 0x機能に依存しますか?
スマの解決策 はかなり有望に見えましたが、機能しません:___imp__*@4
_記号はpointersである必要があります関数自体ではなく、関数。残念ながら、Visual C++がそのような名前の生成でポインターを吐き出す方法はわかりません...(まあ、__declspec(naked)
と___stdcall
_を組み合わせるとうまくいきますが、その後tポインターを出す方法を知っている)。
ビルド時にアセンブラを使用しても問題がなければ、ソリューションはかなり簡単です。次のコードを [〜#〜] fasm [〜#〜] でアセンブルし、生成されたオブジェクトファイルにリンクして、プレストします。 -exeにEncodePointer/DecodePointerの参照がありません:
_use32
format ms coff
section ".data" data
public __imp__DecodePointer@4
__imp__DecodePointer@4 dd dummy
public __imp__EncodePointer@4
__imp__EncodePointer@4 dd dummy
section ".text" code
dummy:
mov eax, [esp+4]
retn 4
_
2008 CRTは使用できませんが、新しい関数DecodePointer/EncodePointerがカーネルからリンクされるのを防ぐことができます。新しい関数をスタブに置き換えるのは非常に簡単です。
以下を試みるかもしれません: このようなコードをmain.cppソースに配置します。
extern "C" { void *__stdcall _imp__DecodePointer(void *x) {return x;} void *__stdcall _imp__EncodePointer(void *x) {return x;} };
上記は動作しません。基本的な考え方は確かですが、実行は少し異なる必要があります。 snemarchのコメントと 別の答え で説明されているように、__imp__
は関数呼び出しではなく、それへのポインタにすぎません。コンパイラーで直接ポインターを生成することはできないように思われるため、MASMを使用して以下のコードをアセンブルし、生成されたオブジェクトファイルにリンクする必要があります。
.model flat
.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD
.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp
end
プロジェクトのシンボルは、ライブラリのシンボルよりも優先されます。 DLLライブラリは、実際の関数にジャンプする__imp__
"vectors"のみを含む.libパーツを使用してリンクされます。__imp__
"vectors"を置き換えることにより、 DLLリンクすると、.lib部分が置き換えられます。DecodePointer/ EncodePointerに対するexeの依存関係がなくなったことを確認しました。
静的にリンクされたライブラリは、使用された機能のみをアプリケーションにもたらします。リンカーの詳細な進行状況出力を使用して、特定のCRT関数がこれらの新しいAPIをもたらすかどうかを見つけることができます。
Found __imp__EncodePointer@4
Referenced in LIBCMT.lib(crtmboxw.obj)
Referenced in LIBCMT.lib(invarg.obj)
Referenced in LIBCMT.lib(handler.obj)
Referenced in LIBCMT.lib(onexit.obj)
Referenced in LIBCMT.lib(cmiscdat.obj)
Referenced in LIBCMT.lib(tidtable.obj)
Referenced in LIBCMT.lib(hooks.obj)
Referenced in LIBCMT.lib(winsig.obj)
Referenced in LIBCMT.lib(Rand_s.obj)
Found __imp__DecodePointer@4
// ... same list, only order differs ...
これは、新しいAPIが一部のCRTで使用され、頻繁な攻撃ベクトルを提供すると見なされる一部の機能のセキュリティを強化することを示しています。
少し努力すれば、LoadLibrary/GetProcAddressを使用して、OSが提供する実際の機能を提供することは可能ですが、実際には何ももたらさないと思います。 DecodePointer/EncodePointerを使用するランタイム関数は、実際にエンコーディングを提供する必要はありません。必要なのは、対称によるエンコーディングのみです。あなたは本当に強化されたセキュリティを必要としません(VS 2008ランタイムはあなたにそれを与えません)。
Win2kやXP SP2以前のシステム)へのアクセス権がないため、他の障害があなたを待っていないことを願っています。そのため、試すことができません。このようなシステムでexeを起動しようとすると、簡単に変更できるはずです。
最も簡単な解決策は、VS2010のプロジェクト設定のプラットフォームツールセットを、Visual Studio 2008のライブラリとコンパイラを使用するv900に設定することです。これはまた、auto
のようなC++ 0x機能を失うことを意味しますが、正直に言うと、いくつかのtypedef
sでの回避は、CRTの独自のバージョンや他のより複雑なソリューションを構築するよりもおそらく簡単です。 。または、VS2008を使用してください!あなたのアプリケーションにとって重要な他のC++ 0x機能があるかどうかはわかりませんが、あなたは言及しませんでした-std::regex
以外は、テクニカルレポートのv900ツールセットにまだあると思います1名前空間(std::tr1::regex
)。
私が得た印象から、VS2010ライブラリを実行することの不便さを予測しますXP SP1はC++ 0x機能の便利さよりも大きいので、全体的にはそうではありません価値がある。
Visual StudioにはMASMのサポートが付属しているため(プロジェクトのプロパティ->ビルドのカスタマイズ...を参照)、snemarchのコードをMASMに変換する次の変換が役立つ場合があります。
.model flat
.data
__imp__EncodePointer@4 dd dummy
__imp__DecodePointer@4 dd dummy
EXTERNDEF __imp__EncodePointer@4 : DWORD
EXTERNDEF __imp__DecodePointer@4 : DWORD
.code
dummy proc
mov eax, [esp+4]
ret 4
dummy endp
end
また、Windows 2000で実行するには、Linker-> System-> Minimum Required Versionを5.0(デフォルトは5.1)に設定してください。
この問題の通常の回避策は、CRTの独自のカスタムバージョンをビルドすることです。そのための指示があります ここ 。 EncodePointer
とDecodePointer
を無視するには、コードを編集する必要があります。 (そのための#define
がすでにあるはずです。)
あなたがする必要がある他の2つのマイナーなことがあります:
C:\Microsoft Visual Studio 9.0\VC\lib
を最初の検索パスとして設定します。 (デフォルトのインストールディレクトリを使用していることを前提としていますが、それ以外の場合は適宜変更します。)これにより、プログラムをWindows 2000およびそれ以降のバージョンで実行できるようになります。
DLLの使用が許可されている場合、これははるかに簡単です。基本的に、リンカーの/ ENTRYPOINT関数を使用して、Cランタイム関数をまったく必要としないEXEを記述します。基本的な前提条件が満たされていることをテストし、すべてのターゲットOS(つまりMessageBox)で利用可能なWindows提供のAPIのみを介してユーザーに問題を報告したら、LoadLibraryを呼び出してDLLを開始しますロジックの大部分が含まれています。そのDLLは通常どおりVS2010ランタイムを使用できます。起動時にメイン.EXE内に含まれるリソースからDLLを解凍することで、2つの個別のファイルの展開を回避することもできます。 (これは、.DLLをディスクに書き込まずにメモリ内で完全に実行できますが、Windows PEローダーを利用してすべてのインポートを修正する場合はできません)。
オプション1-問題のAPI呼び出しを指定したDLLにリダイレクトする2010ランタイムの変更バージョンを作成します。これがどれほど簡単か難しいかわかりません-できればマイナーシンボルテーブルを微調整しますが、ファイル形式によって異なります。もちろん、ライセンスのリバースエンジニアリング条項に遭遇する可能性が非常に高くなります。
オプション2-ランタイムライブラリの2つの異なるバージョンでエクスポートされたシンボルを比較します。シンボルが同じである場合、互換性は十分にありますが、保証はありません。 libファイルの形式が異なる可能性もあります。
オプション3-特にパッチを適用したバージョンを作成するために、MSDNまたは同様の方法でランタイムソースにアクセスできるかどうかを確認します。
オプション4-2010コンパイラを使用できるかどうかを確認しますが、おそらくカスタムビルドステップとしてソリューションで構成された古いリンカーを使用します。繰り返しますが、これはobjファイルとlibファイルが同じファイル形式であるかどうかによって異なりますが、小さなユーティリティを記述して、ヘッダーのバージョン番号などの単純な違いにパッチを適用できる場合があります。古いコンパイラーは、以前のランタイムでリンクしても問題ないはずです-新しいコンパイラーのobjがそれと互換性があると仮定します。
オプション5-独自のランタイムを必要としないが、古いコンパイラーを使用してビルドされたアプリケーションによってロードおよびホストされるDLLを2010年にビルドします。 DLLの「ランタイムなし」の要件を実現するには、もちろん、多くのライブラリをホスティングアプリケーションにビルドする必要があり、作業する必要のあるライブラリ関数に独自のインターフェイスを(ホストアプリケーションを介して)提供する必要がある場合があります。あり-特にメモリ割り当てに関するもの。
確認する価値のあるオプションですが、すでにすべてを考えていると思います。申し訳ありませんが、どれかが機能するかどうか、またはほとんど機能するが断続的な問題が発生するかどうかはわかりません。
不足している機能を実装する.LIBを作成し、KERNEL32.LIBの前にリンクします。
Kernel2.libの前にw2kcompat.libを配置できるように、リンカーオプション/NODEFAULTLIB:kernel32.libを使用する必要があります。