web-dev-qa-db-ja.com

Visual Studio 2010のC ++コンパイラをVisual Studio 2008のC ++ランタイムライブラリと共に使用できますか?

Windows 2000で動作する必要のあるアプリケーションがあります。VisualStudio 2010も使用したいと思います(主にautoキーワードの定義が変更されたため)。ただし、古いOSでアプリを操作できるようにする必要があるため、私は少し困っています。

  • Windows 2000
  • Windows XP RTM
  • Windows XP SP1

Visual Studio 2010のランタイムライブラリは、Windowsで導入されたEncodePointer / DecodePointer AP​​Iに依存していますXP SP2。

代替ランタイムライブラリを使用できる場合、このブレークコードはstd::regexなどのVS2010で追加されたC++ 0x機能に依存しますか?

36
Billy ONeal

スマの解決策 はかなり有望に見えましたが、機能しません:___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
_
11
snemarch

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を起動しようとすると、簡単に変更できるはずです。

24
Suma

最も簡単な解決策は、VS2010のプロジェクト設定のプラットフォームツールセットを、Visual Studio 2008のライブラリとコンパイラを使用するv900に設定することです。これはまた、autoのようなC++ 0x機能を失うことを意味しますが、正直に言うと、いくつかのtypedefsでの回避は、CRTの独自のバージョンや他のより複雑なソリューションを構築するよりもおそらく簡単です。 。または、VS2008を使用してください!あなたのアプリケーションにとって重要な他のC++ 0x機能があるかどうかはわかりませんが、あなたは言及しませんでした-std::regex以外は、テクニカルレポートのv900ツールセットにまだあると思います1名前空間(std::tr1::regex)。

私が得た印象から、VS2010ライブラリを実行することの不便さを予測しますXP SP1はC++ 0x機能の便利さよりも大きいので、全体的にはそうではありません価値がある。

24
AshleysBrain

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)に設定してください。

8
Tomasz Grobelny

この問題の通常の回避策は、CRTの独自のカスタムバージョンをビルドすることです。そのための指示があります ここEncodePointerDecodePointerを無視するには、コードを編集する必要があります。 (そのための#defineがすでにあるはずです。)

あなたがする必要がある他の2つのマイナーなことがあります:

  • リンカー->追加のライブラリディレクトリ設定に移動し、C:\Microsoft Visual Studio 9.0\VC\libを最初の検索パスとして設定します。 (デフォルトのインストールディレクトリを使用していることを前提としていますが、それ以外の場合は適宜変更します。)
  • PEヘッダーのサブシステムバージョンを5.00に変更します(他に便利なツールがない場合は、無料の CFF Explorer Suite を使用してください)。

これにより、プログラムをWindows 2000およびそれ以降のバージョンで実行できるようになります。

4
Head Geek

DLLの使用が許可されている場合、これははるかに簡単です。基本的に、リンカーの/ ENTRYPOINT関数を使用して、Cランタイム関数をまったく必要としないEXEを記述します。基本的な前提条件が満たされていることをテストし、すべてのターゲットOS(つまりMessageBox)で利用可能なWindows提供のAPIのみを介してユーザーに問題を報告したら、LoadLibraryを呼び出してDLLを開始しますロジックの大部分が含まれています。そのDLLは通常どおりVS2010ランタイムを使用できます。起動時にメイン.EXE内に含まれるリソースからDLLを解凍することで、2つの個別のファイルの展開を回避することもできます。 (これは、.DLLをディスクに書き込まずにメモリ内で完全に実行できますが、Windows PEローダーを利用してすべてのインポートを修正する場合はできません)。

3
Ben Voigt

オプション1-問題のAPI呼び出しを指定したDLLにリダイレクトする2010ランタイムの変更バージョンを作成します。これがどれほど簡単か難しいかわかりません-できればマイナーシンボルテーブルを微調整しますが、ファイル形式によって異なります。もちろん、ライセンスのリバースエンジニアリング条項に遭遇する可能性が非常に高くなります。

オプション2-ランタイムライブラリの2つの異なるバージョンでエクスポートされたシンボルを比較します。シンボルが同じである場合、互換性は十分にありますが、保証はありません。 libファイルの形式が異なる可能性もあります。

オプション3-特にパッチを適用したバージョンを作成するために、MSDNまたは同様の方法でランタイムソースにアクセスできるかどうかを確認します。

オプション4-2010コンパイラを使用できるかどうかを確認しますが、おそらくカスタムビルドステップとしてソリューションで構成された古いリンカーを使用します。繰り返しますが、これはobjファイルとlibファイルが同じファイル形式であるかどうかによって異なりますが、小さなユーティリティを記述して、ヘッダーのバージョン番号などの単純な違いにパッチを適用できる場合があります。古いコンパイラーは、以前のランタイムでリンクしても問題ないはずです-新しいコンパイラーのobjがそれと互換性があると仮定します。

オプション5-独自のランタイムを必要としないが、古いコンパイラーを使用してビルドされたアプリケーションによってロードおよびホストされるDLLを2010年にビルドします。 DLLの「ランタイムなし」の要件を実現するには、もちろん、多くのライブラリをホスティングアプリケーションにビルドする必要があり、作業する必要のあるライブラリ関数に独自のインターフェイスを(ホストアプリケーションを介して)提供する必要がある場合があります。あり-特にメモリ割り当てに関するもの。

確認する価値のあるオプションですが、すでにすべてを考えていると思います。申し訳ありませんが、どれかが機能するかどうか、またはほとんど機能するが断続的な問題が発生するかどうかはわかりません。

3
Steve314

不足している機能を実装する.LIBを作成し、KERNEL32.LIBの前にリンクします。

Kernel2.libの前にw2kcompat.libを配置できるように、リンカーオプション/NODEFAULTLIB:kernel32.libを使用する必要があります。

0
Gideon7