32

最終的な目標は、まったく同じ環境でまったく同じソースから構築された2つのバイナリを比較し、それらが実際に機能的に同等であることを確認できるようにすることです。

このための1つのアプリケーションは、リリース間で実際に変更されたものにQA時間を集中させることと、一般的な変更の監視です。

PE形式と連携したMSVCは、当然これを行うのを非常に困難にします。

これまでのところ、私はそれらのものを見つけて中和しました:

  • PEタイムスタンプとチェックサム
  • デジタル署名ディレクトリエントリ
  • デバッガーセクションのタイムスタンプ
  • PDBの署名、経過時間、ファイルパス
  • リソースのタイムスタンプ
  • VS_VERSION_INFOリソース内のすべてのファイル/製品バージョン
  • デジタル署名セクション

私はPEを解析し、それらすべてのオフセットとサイズを見つけ、バイナリを比較するときにバイト範囲を無視します。チャームのように機能します(まあ、私が実行したいくつかのテストでは)。Win Server 2008でビルドされたバージョン1.0.2.0の署名された実行可能ファイルは、コンパイラのバージョンとすべてのソースとヘッダーが同じである限り、WinXP開発ボックスでビルドされたバージョン10.6.6.6の署名されていない実行可能ファイルと同じであることがわかります。これはVC7.1-9.0で機能するようです。(リリースビルドの場合)

注意点が1つあります。

両方のビルドの絶対パス は同じである 必要があり、同じ長さである必要があります。

cl.exeは相対パスを絶対パスに変換し、コンパイラフラグなどとともにオブジェクトに直接配置します。これは、バイナリ全体に不均衡な影響を及ぼします。パスを1文字変更すると、.textセクション全体で1バイトが何度か変更されます(ただし、リンクされているオブジェクトの数は多いと思います)。パスの長さを変更すると、大幅に多くの違いが生じます。objファイルとリンクされたバイナリの両方。

コンパイルフラグ付きのファイルパスが何らかのハッシュとして使用されているように感じます。これにより、リンクされたバイナリになり、コンパイルされたコードの無関係な部分の配置順序に影響を与えることさえあります。

それで、ここに3部構成の質問があります(「今何?」として要約されます):

  • 私がやろうとしていることは、MSの物理法と企業方針に違反しているので、プロジェクト全体を放棄して家に帰るべきですか?

  • 絶対パスの問題を(ポリシーレベルで、または魔法のコンパイラフラグを見つけることによって)処理すると仮定すると、他に注意すべき点はありますか?(__TIME__のようなもの変更されたコードを意味するので、無視されなくてもかまいません)

  • コンパイラに相対パスを使用させる方法、またはパスが実際のパスではないと思わせる方法はありますか?

最後の理由は、美しく迷惑なWindowsファイルシステムです。いくつかのギグに相当するソースとオブジェクトをいつ削除するかはわかりません。不正なファイルロックが原因でsvnメタデータが失敗します。少なくとも、スペースが残っている間は、新しいルートの作成は常に成功します。一度に複数のビルドを実行することも問題です。大量のVMを実行することは、解決策ではありますが、かなり重いものです。

プロセスとその子の仮想ファイルシステムをセットアップして、複数のプロセスツリーが同時にプライベートな異なる「C:\build」ディレクトリを表示するようにする方法があるのではないかと思います...ライト-ある種のウェイト仮想化...

更新:最近、GitHubでツールをオープンソース化しました。ドキュメントの比較セクションを参照してください。

4

5 に答える 5

13

私はこれをある程度解決しました。

現在、すべての新しいビルドが一定の長さのパス(builds / 001、builds / 002など)上にあることを確認するビルドシステムがあり、PEレイアウトのシフトを回避しています。ビルド後、ツールは、関連するPEフィールドやその他の場所を無視して、古いバイナリと新しいバイナリを比較し、既知の表面的な変更を加えます。また、動的な無視できる変更を検出するために、いくつかの単純なヒューリスティックを実行します。無視するものの完全なリストは次のとおりです。

  • PEタイムスタンプとチェックサム
  • デジタル署名ディレクトリエントリ
  • テーブルのタイムスタンプをエクスポート
  • デバッガーセクションのタイムスタンプ
  • PDBの署名、経過時間、ファイルパス
  • リソースのタイムスタンプ
  • VS_VERSION_INFOリソース内のすべてのファイル/製品バージョン
  • デジタル署名セクション
  • 埋め込み型ライブラリ用のMIDLバニティスタブ(タイムスタンプ文字列を含む)
  • リテラル文字列として使用される場合の__FILE__、__ DATE__、および__TIME__マクロ(幅の広い文字または幅の狭い文字)

たまに、リンカーは、他のものを整列から外すことなく、いくつかのPEセクションを大きくします。パディング内のセクション境界を移動するように見えます-とにかくそれはすべてゼロですが、それのために私は1バイトの違いを持つバイナリを取得します。

更新:最近、GitHubでツールをオープンソース化しました。ドキュメントの比較セクションを参照してください。

于 2012-05-15T17:29:18.250 に答える
8

ビルドパスの標準化

簡単な解決策は、ビルドパスを標準化することです。したがって、ビルドパスは常に次の形式になります。

c:\buildXXXX

次に、たとえばbuild0434build0398を比較する場合は、バイナリを前処理して、build0434のすべてのオカレンスをbuild0398に変更します。コンパイラ/リンカがPEに埋め込まれている文字列を除いて、実際のソース/データに表示される可能性が低いことがわかっているパターンを選択してください。

次に、通常の差異分析を行うことができます。同じ長さのパス名を使用することで、データをシフトしたり、誤検知を引き起こしたりすることはありません。

ダンプビンユーティリティ

もう1つのヒントは、dumpbin.exe(MSVCに付属)を使用することです。dumpbin / allを使用して、バイナリのすべての詳細をテキスト/16進ダンプにダンプします。これにより、何がどこで変化しているかをより明確に確認できます。

例えば:

dumpbin /all program1.exe > program1.txt
dumpbin /all program2.exe > program2.txt
windiff program1.txt program2.txt

または、Windiffの代わりに、お気に入りのテキスト差分ツールを使用してください。

Bindiffユーティリティ

Microsoftのbindiff.exeツールが役立つ場合があります。これは次の場所から入手できます。

Windows XP ServicePack2サポートツール

タイムスタンプ、チェックサムなどの特定のバイナリフィールドを無視するように指示する/vオプションがあります。

「BinDiffは、Win32実行可能ファイル用の特別な比較ルーチンを使用して、比較を実行するときに両方のファイルのさまざまなビルドタイムスタンプフィールドをマスクします。これにより、ファイルが真に同一である場合に、2つの実行可能ファイルを「ほぼ同一」としてマークできます。彼らが建てられた時。」

ただし、bindiff.exeの機能のスーパーセットをすでに実行しているようです。

于 2009-07-25T01:24:59.150 に答える
3

実行可能ファイルを逆アセンブルして、逆アセンブルを比較してみましたか?それはあなたが言及する多くの気が散る詳細を削除し、他のものをはるかに簡単に削除できるようにするはずです。

于 2009-07-25T01:07:48.180 に答える
3

コンパイラに相対パスを使用させる方法、またはパスが実際のパスではないと思わせる方法はありますか?

これを行うには2つの方法があります。

  1. subst.exeコマンドを使用して、ドライブ文字をビルドフォルダーにマップします(これは信頼できない場合があります)。
  2. subst.exeが機能しない場合は、ビルドフォルダーごとに共有を作成し、「netuse」コマンドを使用します。これはほぼ確実に機能するはずです。

いずれの場合も、特定のビルドを開始する前に、フォルダーに同じドライブ文字をマップして再利用するため、パスはコンパイラーと同じように見えます。

于 2009-07-25T01:28:50.347 に答える
1

この問題を解決するのに役立つ追加のツールに出くわしました: GitHubのDucible

「これは、Portable Executable(PE)とPDBのビルドを再現可能にするためのツールです。」

提供されている*.exe、*。dll、および* .pdbファイルを適切に変更し、非決定論的データを決定論的データに置き換えます。

于 2021-04-20T20:20:13.390 に答える