8

Cで関数の内容をメモリにコピーして実行する方法を知りたいですか?

私はこのようなことをしようとしています:

typedef void(*FUN)(int *);
char * myNewFunc;

char *allocExecutablePages (int pages)
{
    template = (char *) valloc (getpagesize () * pages);
    if (mprotect (template, getpagesize (), 
          PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
        perror ("mprotect");
    } 
}

void f1 (int *v) {
    *v = 10;
}

// allocate enough spcae but how much ??
myNewFunc = allocExecutablePages(...)

/* Copy f1 somewere else
 * (how? assume that i know the size of f1 having done a (nm -S foo.o))
 */

((FUN)template)(&val);
printf("%i",val);

回答ありがとうございます

4

5 に答える 5

6

保護フラグに関する部分を理解したようです。関数のサイズがわかっている場合は、memcpy() を実行して、ソース アドレスとして f1 のアドレスを渡すことができます。

1 つの大きな注意点は、多くのプラットフォームでは、コピーしている関数 (f1) から他の関数​​を呼び出すことができないということです。これは、相対アドレスが関数のバイナリ コードにハードコードされており、それを別の場所に移動しているためです。メモリがこれらの相対アドレスを無効にする可能性がある場合。

于 2010-12-28T13:08:51.447 に答える
3

function1 と function2 がメモリ内でまったく同じサイズであるため、これはたまたま機能します。memcopy には function2 の長さが必要なので、次のようにします。 int diff = (&main - &function2);

機能 2 を好みに合わせて編集でき、問題なく機能し続けることがわかります。

Btw neat trick. Unfurtunate the g++ compiler does spit out invalid conversion from void* to int... But indeed with gcc it compiles perfectly ;)

Modified sources:

//Hacky solution and simple proof of concept that works for me (and compiles without warning on Mac OS X/GCC 4.2.1):
//fixed the diff address to also work when function2 is variable size    
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){ 
   return x-5;
}   

int function2(int x){ 
  //printf("hello world");
  int k=32;
  int l=40;
  return x+5+k+l;
}   


int main(){
  int diff = (&main - &function2);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }   

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}   

Output:

Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ gcc memoryFun.c 
Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ ./a.out 
pagesize: 4096, diff: 35
native: 1
memory: 83
native: 1

Another to note is calling printf will segfault because printf is most likely not found due to relative address going wrong...

于 2012-03-02T18:00:20.410 に答える
1

私にとってはうまくいく(そしてMac OS X / GCC 4.2.1で警告なしにコンパイルされる)ハッキーなソリューションと単純な概念実証:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){
   return x-5;
}

int function2(int x){
  return x+5;
}


int main(){
  int diff = (&function2 - &function1);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}
于 2012-01-09T20:32:22.283 に答える
0

私はこの問題を C で何度も試しましたが、C 言語だけでは解決できないという結論に達しました。私の主な問題は、コピーする関数の長さを見つけることでした。

標準 C 言語には、関数の長さを取得するメソッドはありません。ただし、アセンブリ言語と「セクション」を使用して長さを見つけることができます。長さが分かれば、コピーして実行するのは簡単です。

最も簡単な解決策は、関数を含むリンカー セグメントを作成または定義することです。このセグメントの長さを計算して公に宣言するアセンブリ言語モジュールを作成します。この定数を関数のサイズに使用します。

事前定義された領域または固定された場所など、リンカーの設定を含む他の方法があり、それらの場所をコピーします。

組み込みシステムの世界では、実行可能なものを RAM にコピーするコードのほとんどがアセンブリで記述されています。

于 2010-12-28T18:04:18.687 に答える
0

これはここでのハックソリューションかもしれません。関数の直後に(コピーする)ダミー変数または関数を作成し、そのダミー変数/関数のアドレスを取得してから、関数のアドレスを取得して、アドレスを使用して合計ソート算術を実行し、関数のサイズを取得できますか? これは、メモリが (ランダムではなく) 線形かつ整然と割り当てられるため、可能になる可能性があります。これにより、システム固有のアセンブリ コードを掘り下げるのではなく、ANSI C の移植可能な性質内で関数のコピーを維持することもできます。C はかなり柔軟であることがわかりました。物事を考える必要があるだけです。

于 2011-09-12T16:07:55.650 に答える