2

スタックをアンワインドし、各 CALL に割り当てられたスタック スペースと静的に派生したローカル変数のサイズの間に不一致があるかどうかを判断する機能をデバッガーに追加しています (Ptrace を使用して、トレースされたプロセスと libbfd/libopcodes を操作しています)。途中で各フレームのアドレスとローカルスタックサイズを出力します。

私の一般的な方法論は、ベース ポインター ( EBP/ RBP) でアドレスを取得し、ポインターをインクリメントして格納されたフレーム ポインターを格納し、そのアドレスを逆参照し、それを調べてPTRACE_PEEKDATA、スタック外の領域を占有するアドレスを逆参照するまで繰り返します。

コード/データ セグメント レジスタをチェックする方法は知っていますが、理想的には、W^X メモリ ページまたは実行不可能なスタックによってセグメンテーションが変更された場合でも、まだコールスタック内にあるかどうかをチェックする方法が必要です。

要するに、一般保護違反をトリガーせずにスタックの外に移動したとき、どのように確認できますか (一般的な場合)。

(余談ですが、ここではアドレスのページセグメントをチェックすることが理想的な方法であるという前提で操作していることに気付きました。おそらく、アドレスが現在のプロセスのスタックスペース内にあるかどうかを判断するための別の簡単な方法が存在します)

4

2 に答える 2

1

C 標準は、OS 固有またはハードウェア固有の情報や機能にアクセスする移植可能な方法を提供していません (おそらく system() を除く)。C プログラムが上記の情報/機能に依存している場合、移植性が低くなる運命にあります。

POSIX 機能に固執する場合、移植性がいくらか向上する可能性がありますが、その改善は POSIX 準拠 OS の改善にすぎません。それ以外の場合は、改善の反対になります。同様に、Linux で常に利用できるもの (特定の関数、ツール、またはライブラリ) を使用できる場合もあります。私はあなたにそのようなことを指摘することはできません。さらに調査を行うか、他の回答を待つ必要があります。

于 2013-04-05T15:04:47.643 に答える
0

実行中のプロセスのスタックの内容を出力しているpstackコマンドのコードを見ました。link_mapこのコードは、構造体からベース アドレスを取得し、フィールド内に格納していますl_addr。このフィールドは関数内で設定されますreadLinkMap():

static void readLinkMap(int pid, ElfN_Addr base, struct link_map *lm, 
                        char *name, unsigned int namelen)
{
  /* base address */
  lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
                                  base + offsetof(struct link_map,l_addr), 0);
  /* next element of link map chain */
  if (-1 != (long) lm->l_addr || !errno)
    lm->l_next = (struct link_map *) ptrace(PTRACE_PEEKDATA, pid,
                                            base + offsetof(struct link_map, l_next), 0);
  if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) {
    perror("ptrace");
    quit("can't read target.");
  }

  loadString(pid, base + offsetof(struct link_map, l_name), name, namelen);
}
于 2013-04-05T21:21:13.340 に答える