5

自己変更コードに関するコードブレーカーのジャーナル記事を読んでいたところ、次のコード スニペットがありました。

void Demo(int (*_printf) (const char *,...))
{ 
      _printf("Hello, OSIX!n"); 
      return; 
} 
int main(int argc, char* argv[]) 
{ 
  char buff[1000]; 
  int (*_printf) (const char *,...); 
  int (*_main) (int, char **); 
  void (*_Demo) (int (*) (const char *,...)); 
  _printf=printf; 
  int func_len = (unsigned int) _main ­- (unsigned int) _Demo; 
  for (int a=0; a<func_len; a++) 
    buff[a] = ((char *) _Demo)[a]; 
  _Demo = (void (*) (int (*) (const char *,...))) &buff[0]; 
  _Demo(_printf); 
  return 0; 
}

このコードは、スタック上で Demo() を実行したと思われます。ほとんどのコードは理解できますが、「func_len」が割り当てられている部分で混乱します。私が知る限り、彼らは別のランダム ポインター アドレスから 1 つのランダム ポインター アドレスを減算しています。

誰か説明してくれませんか?

4

2 に答える 2

7

コードは、コンパイラからの関数のレイアウトに関する知識に依存しています。これは、他のコンパイラでは信頼できない場合があります。

行はfunc_len、最初に欠落していた を含むように修正されると、アドレス in (の開始アドレスを含むと想定される) からアドレス in (の開始アドレスを含むと想定される)を減算することによって-、関数の長さを決定します。 )。これは関数の長さと推定され、バイト単位でバッファにコピーされます。のアドレスは関数ポインタに変換され、関数が呼び出されます。ただし、どちらも実際には初期化されていないため、コードは極端にバグがあります。また、 anがポインターを正確に保持するのに十分な大きさであるかどうかも明らかではありません。キャストはおそらくfromにする必要がありますDemo_DemoDemo()_mainmain()Demobuffbuff_Demo_mainunsigned intuintptr_t<stdint.h>または<inttypes.h>

これは、バグが修正されている場合、コード レイアウトに関する仮定が正しい場合、コードが位置に依存しないコードである場合、およびデータ スペースの実行に対する保護がない場合に機能します。信頼性が低く、移植性がなく、お勧めできません。しかし、それが機能する場合、コードとデータが非常に似ていることを示しています。

2 つのプロセス間で同様のスタントを行い、一方のプログラムから共有メモリに関数をコピーし、もう一方のプログラムに共有メモリからその関数を実行させたのを覚えています。それは約四半世紀前のことでしたが、技術は類似しており、それが試されたマシンで「機能しました」. それ以来、このテクニックを使用する必要はありませんでした。

于 2011-04-26T06:33:19.560 に答える
5

このコードは、初期化されていない変数_main_Demoを使用しているため、一般的には機能しません。たとえ別のことを意味していたとしても、メモリ内の関数の特定の順序を想定していた可能性があります。

私の意見: この記事を信用しないでください。

于 2011-04-26T06:24:19.503 に答える