9

独自のグローバル定数を変更して、実行可能ファイルの状態を保存したいと考えています。完全に自己完結型の実行可能ファイルを用意するためだけに。

頭に浮かぶいくつかの解決策/ハック:

  1. libelf を使用し、プログラムにそれ自体を解析させてオフセットを見つけます。
  2. 特定のマーカーを追加し、実行可能ファイルで検索するだけです。これはクロスプラットフォームでもあると思いますか?
  3. オブジェクト ダンプ ユーティリティを使用して、実行可能ファイル内のアドレスを特定します。これはおそらく、プロジェクト ビルドの後処理として常に実行する必要があります。

リンカーにこの情報を提供してもらうのはいいことです。

リンカーに実行可能ファイルの読み取り専用セクションのオフセットを提供させることは可能ですか?

ありがとう

4

3 に答える 3

6

あなたがやりたいことは、トリッキーで移植性がありません。

ただし、 src/unexelf.cなどでGNU emacsunexec機能を調べることができます(Linux の場合。他の OS にも同様のファイルがあります)。

ldたとえば独自のスクリプトを使用して、リンカーのトリックを実行することもできます。

これらのトリックは、プロセッサ、コンパイラ、カーネル、および libc のバージョンに固有のものである可能性があることに注意してください。

おそらく、アプリケーションのチェックポイントが必要です。特に、BLCRは役に立つかもしれません。

于 2012-09-23T10:55:21.953 に答える
5

あなたは本質的にバイナリ書き換えについて話している。コンパイル プロセスをいじらずにこれを実現する方法の 1 つは、仮想アドレスを物理アドレスにマップしてからパッチを適用することです。興味深いことに、これは私が修士論文で取り上げたものです。次の画像とテキストは、そのドキュメントから抽出されたものです。

http://localhostr.com/file/hyB1iFuiL0nV/Loading_Binary.jpg

私の元のプロジェクトの背後にある概念は、コンパイル プロセスを変更できないと仮定して、他のバイナリのコードを書き直すことでした。要件と仮定が異なる場合、これは最も簡単で最善の方法ではない可能性があります。

ここで最も重要な考え方は、ディスク表現のセクションがメモリにマップされるときに保持される (分割されない) ということです。これは、ディスク表現のセクションへの特定のオフセットにあるデータが、メモリにロードされた後に同じ量だけオフセットされることを意味します。

ではlibelf、 と同様にlibbfd、実行可能ファイルには、コードとデータの両方を配置できる一連のセクションが含まれています。オペレーティング システムが実行可能ファイルをメモリにロードするとき、各セクションは何らかのベース アドレスに基づいています。これを逆にして、仮想メモリ アドレスを物理ファイル オフセットにマップできます。物理ファイルのオフセットが見つかった場合は、バイトを通常のファイルとしてパッチできます。

  • まず、実行可能ファイルのセクション ヘッダーが で解析されlibelfます。これにより、一連のセクションを取得できます。最も重要なことは、各セクションlibelfが次の 3 つのことを教えてくれることです。
    1. セクション サイズ セクションのサイズ。
    2. セクション ベース アドレスディスク上の実行可能ファイルがメモリにロードされるときのセクションのベースとなるアドレス。
    3. セクション ディスク オフセット セクションのディスク オフセット。
  • 前のステップで抽出されたセクション情報を繰り返し処理することにより、任意の仮想メモリ アドレスがどのセクションに含まれているかを見つけることができます。書かれる。セクションへの仮想メモリ アドレスのオフセットは、 で計算できます(virtual_memory_address - section_base_address)
  • したがって、仮想メモリ アドレスのディスク オフセットは で計算できます(section_disk_offset + (virtual_memory_address - section_base_address))

このプロセスにより、任意の仮想メモリ アドレスを対応するディスク ファイル オフセットにマップできます。このオフセットは、 // fopen/などの通常の C ファイル IO 関数でパッチできます。fseekfwritefclose

これは、上記の手順を使用して仮想アドレスを物理ファイル オフセットにマッピングするための私のコードです。

/*
 * Returns the corresponding 32 bit executable file offset of a virtual memory
 * address.
 */
uint32_t vaddr32_to_file_offset(char * filepath, uint32_t vaddr)
{
    int      fd     = open(filepath, O_RDONLY);
    Elf *    e      = elf_begin(fd, ELF_C_READ, NULL);
    uint32_t offset = 0;

    Elf_Scn * scn = NULL;
    while((scn = elf_nextscn(e, scn)) != NULL) {
        Elf32_Shdr * shdr = elf32_getshdr(scn);
        if(vaddr >= shdr->sh_addr &&
                (vaddr <= (shdr->sh_addr + shdr->sh_size))) {
            offset = shdr->sh_offset + (vaddr - shdr->sh_addr);
            break;
        }
    }

    elf_end(e);
    close(fd);
    return offset;
}

/*
 * Returns the corresponding 64 bit executable file offset of a virtual memory
 * address.
 */
uint64_t vaddr64_to_file_offset(char * filepath, uint64_t vaddr)
{
    int      fd     = open(filepath, O_RDONLY);
    Elf *    e      = elf_begin(fd, ELF_C_READ, NULL);
    uint64_t offset = 0;

    Elf_Scn * scn = NULL;
    while((scn = elf_nextscn(e, scn)) != NULL) {
        Elf64_Shdr * shdr = elf64_getshdr(scn);
        if(vaddr >= shdr->sh_addr &&
                (vaddr <= (shdr->sh_addr + shdr->sh_size))) {
            offset = shdr->sh_offset + (vaddr - shdr->sh_addr);
            break;
        }
    }

    elf_end(e);
    close(fd);
    return offset;
}

これは、オフセットを指定して ELF 実行可能ファイルにパッチを適用するコードです。

/*
 * Sets the bytes at an arbitrary offset of a file to the contents of buffer.
 */
static bool patch_file(char * filepath, uint64_t offset, void * buffer,
        size_t size)
{
    FILE * pFile = fopen(filepath, "r+");

    if(pFile == NULL) {
        return FALSE;
    }

    fseek(pFile, offset, SEEK_SET);
    fwrite(buffer, 1, size, pFile);
    fclose(pFile);
    return TRUE;
}

より詳細な情報は、ここで公開されているレポート自体に記載されています。

于 2012-09-23T11:37:49.943 に答える
4

可能であれば、コンパイラは通常、グローバル定数と静的定数をマシンコードの即値として置き換えるため、これは不可能です。例えば:

const int x=3;

int main()
{
 return x;
}

main() に対して次のコードを生成します (OSX/gcc -O3):

_main:
Leh_func_begin1:
    pushq   %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    movl    $3, %eax // <= immediate constant!
    popq    %rbp
    ret
于 2012-09-23T11:21:28.547 に答える