1

関数をコピーして呼び出したいのですが、バッファを呼び出すときに以下のコードが失敗します。何を変更する必要がありますか?(Linux、x86)

#include <string.h>
#include <malloc.h>
#include <stdio.h>

int foo () { return 12; }
void foo_end () {}

int main () {
  int s = (unsigned long long) foo_end - (unsigned long long) foo;
  int (*f) () = (int (*)()) malloc (s);
  memcpy ((void*) f, (const void*) foo, s);
  printf ("%d %d\n", f (), foo ());
}

編集:実用的な解決策:

#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>

int foo () { return 12; }
void foo_end () {}

int main () {
  int s = (unsigned long long) foo_end - (unsigned long long) foo;
  int (*f) () = (int (*)()) malloc (s);
  memcpy ((void*) f, (const void*) foo, s);
  long ps = sysconf (_SC_PAGESIZE);
  void *fp = (void*) ((unsigned long long) f & ~((unsigned long long) (ps-1)));
  if (mprotect ((void*) fp, ps, PROT_READ | PROT_WRITE | PROT_EXEC)) return -1;
  printf ("%d %d\n", f (), foo ());
}
4

3 に答える 3

9

おっと、そのコードには非常に多くの問題があります。

  1. 関数がメモリ内に順番に配置されており、間にパディングがないことを知ることはできません
  2. 2つの関数へのポインタが減算可能であることを知ることはできません
  3. malloc()によって返されたメモリを呼び出すことができることを知ることはできません

要するに、これをしないでください。

アップデート:

mprotect()Linuxでは、メモリのブロックにアクセス許可を設定するために使用できると思います。私はこれにはルートが必要だと思いましたが、明らかにそうではありません(あなたがあなた自身のプロセスの記憶にいる限り)。

于 2010-09-15T12:21:31.967 に答える
3

データセグメントに実行権限を付与しないOSを使用している可能性があります。

一部の環境では、さまざまなタイプのセキュリティ問題(またはそれらの悪用)を回避するために、データページを実行から保護します。

mprotect()を呼び出して、そのページの実行を有効にし、何が起こったかを報告することを検討してください。

于 2010-09-15T12:22:27.910 に答える
0

これは、組み込みシステムの人々に共通の問題です。この手法は、読み取り専用メモリからランダムアクセスメモリ(書き込みおよび読み取り対応)にコピーするためによく使用されます。標準のCまたはC++を使用した洗練されたソリューションも標準的なソリューションもありません。

より簡単な解決策は、リンカーを使用して、いくつかの新しい非標準のセグメントを定義することです。非標準#pragmaを使用して、関数を新しいセグメントに配置するようにコンパイラーに指示します。非標準のコンパイラ指令を使用して、このセグメントの開始アドレスと終了アドレスにアクセスします。これにより、関数のサイズを取得できます。

宛先のより安全な方法は、実行可能属性と書き込み属性を使用して別のセグメントを作成することです。機能セグメントのデータをこの実行可能セグメントにコピーします。このセグメントの開始を指すように関数ポインタを設定します。ポインタを介して関数を実行します。

別の解決策は、これをアセンブリ言語で実行することです。多くの場合、アセンブラは、より低いレベルでこのようなメモリを操作するためのより多くの自由(足を撃つため)を提供します。

また、オペレーティングシステムローダー、メモリ属性、および保護スキームを確認してください。一部のOSは、この種の動作をカーネル特権以上に制限する場合があります。

于 2010-09-15T19:25:27.383 に答える