1

プログラムで宣言した文字列と関数の間の相関関係を示すファイルからテキストを読み取りたい場所で、c++ で何かを書いています。たとえば、ファイルは次のようになります。

sin:sin
PI:getPi
+:add

コードでこれを取得し、文字列と関数ポインターのデータ構造のハッシュ テーブルまたはベクトルを作成する必要がありました。残念ながら、コードは実行時に関数の名前を見つけることができないことに気付いたので、これらの関数のアドレスをファイルに入れられるようにしたいと考えています。しかし、プログラムが実行またはコンパイルされるたびに関数のアドレスが異なる場合、このシステムはもちろん機能しません。啓蒙、またはこれらの問題のいずれかに対する代替ソリューションは素晴らしいでしょう.

4

3 に答える 3

2

多分?

お使いのシステムは ASLR を使用していますか?

アドレス空間レイアウトのランダム化。最新のシステムで使用されている手法で、エクスプロイトがプライベートまたは特権機能を実行して ROP 攻撃を実行するのを防ぎます。

基本的に、メモリ内の関数の場所をランダム化します。すべてがまだ相対的であるため、ベース イメージの場所がわかっている場合、これは無効になります。0xDEADBEEF+13 のような表記をよく見かけます。

詳細については、 ASLRを参照してください。

于 2013-03-26T22:28:40.850 に答える
2

コンパイル時に関数のアドレス (関数ポインター) を安全に取得できます。プログラムの起動時に関数アドレスを再配置するのは、イメージ ローダー タスクです。関数のアドレスが変わることを心配する必要はありません。

もちろん、関数のアドレスを stdout に出力して、このアドレスを数値としてプログラムに入れることは、してはいけないことです。それはあなたが説明する問題に悩まされるでしょう。

C++ 関数のアドレスを取得するには、コードsin()で使用するだけ&sinです。

C++ 関数のアドレスを文字列で取得するには、次のようなコードが必要です。

if (function_name == "sin") return &sin;
else if (function_name == "add") return &add;
else ...

または、文字列/関数ポインターのペアを持つ適切なデータ構造。

ポイントは、数値関数アドレスをファイルに保存しないことです。プログラムで関数アドレスを直接取得して使用します。数値関数アドレスは、プログラムにとってまったく重要ではありません。

于 2013-03-26T22:29:12.247 に答える
1

OS はアドレス空間レイアウトのランダム化を採用してエクスプロイトの有効性を低下させる可能性があるため、アドレスが固定されていることに依存することはできません。

それらがすべて同じリンクされたバイナリ内にある場合、関数の相対アドレスに依存できる場合あります。ベースとなるものを 1 つ選択し、それを他のすべてから差し引きます。

当然、再コンパイルおよび/または再リンクすると、これはすべてオフになります。別の方法を見つけようと思います。

そのような方法の 1 つは、各関数に整数インデックスを使用し、どのインデックスがどの関数に対応するかのテーブルを保持することです。別の間接レイヤーが導入されますが、はるかに堅牢になります。

編集:静的テーブルを作成したくない場合は、静的オブジェクトとコンストラクターを使用して、プログラムの初期化時にコードで作成することができます。

struct FunctionTable
{
    typedef std::unordered_map<std::string, void *> table;
    static table& get()
    {
        static table the_table;
        return the_table;
    }
    FunctionTable(std::string name, void * func)
    {
        get().insert(name, func);
    }
};

double getPi()
{
    return 3.14159;
}
static FunctionTable ft_getPi = FunctionTable("getPi", getPi);
于 2013-03-26T22:33:13.860 に答える