0

私はバッファ オーバーフローを研究し、いくつかのウォーゲームを解決しています。メインの戻りアドレスを除いて、バッファの上のすべてのスタック メモリが 0 に設定されるという問題がありました。これは次のようになります。

buffer
[0000000...][RET][000000...]

そのRETを上書きできます。そこで、この問題を解決するためのヒントをいくつか見つけました。LD_PRELOAD を使用することでした。LD_PRELOAD の値は、スタックの環境変数領域だけでなく、スタックのどこかにあるという人もいます。そこで、LD_PRELOAD を設定して検索し、gdb を使用して見つけました。

$ export LD_PRELOAD=/home/coffee/test.so
$ gdb -q abcde
(gdb) b main
Breakpoint 1 at 0x8048476
(gdb) r
Starting program: /home/coffee/abcde

Breakpoint 1, 0x8048476 in main ()
(gdb) x/s 0xbffff6df
0xbffff6df:      "@èC\001@/home/coffee/test.so"
(gdb) x/s 0xbffffc59
0xbffffc59:      "LD_PRELOAD=/home/coffee/test.so"
(gdb) q
The program is running.  Exit anyway? (y or n) y
$

あります!これで、LD_PRELOAD の値がバッファの下のスタックにあることがわかり、悪用できるようになりました!

しかし、なぜ LD_PRELOAD がそのメモリ アドレスにロードされるのだろうか。値はスタックの環境変数領域にもあります!

これの目的は何ですか?ありがとう。

4

1 に答える 1

1

スタック レイアウトを調べるコード:

#include <inttypes.h>
#include <stdio.h>

// POSIX 2008 declares environ in <unistd.h> (Mac OS X doesn't)
extern char **environ;

static void dump_list(const char *tag, char **list)
{
    char **ptr = list;
    while (*ptr)
    {
        printf("%s[%d] 0x%.16" PRIXPTR ": %s\n",
               tag, (ptr - list), (uintptr_t)*ptr, *ptr);
        ptr++;
    }
    printf("%s[%d] 0x%.16" PRIXPTR "\n",
           tag, (ptr - list), (uintptr_t)*ptr);
}

int main(int argc, char **argv, char **envp)
{
    printf("%d\n", argc);
    printf("argv         0x%.16" PRIXPTR "\n", (uintptr_t)argv);
    printf("argv[argc+1] 0x%.16" PRIXPTR "\n", (uintptr_t)(argv+argc+1));
    printf("envp         0x%.16" PRIXPTR "\n", (uintptr_t)envp);
    printf("environ      0x%.16" PRIXPTR "\n", (uintptr_t)environ);

    dump_list("argv", argv);
    dump_list("envp", envp);
    return(0);
}

としてコンパイルされたプログラムxを使用して、サニタイズされた環境で実行しました。

$ env -i HOME=$HOME PATH=$HOME/bin:/bin:/usr/bin LANG=$LANG TERM=$TERM ./x a bb ccc
4
argv         0x00007FFF62074EC0
argv[argc+1] 0x00007FFF62074EE8
envp         0x00007FFF62074EE8
environ      0x00007FFF62074EE8
argv[0] 0x00007FFF62074F38: ./x
argv[1] 0x00007FFF62074F3C: a
argv[2] 0x00007FFF62074F3E: bb
argv[3] 0x00007FFF62074F41: ccc
argv[4] 0x0000000000000000
envp[0] 0x00007FFF62074F45: HOME=/Users/jleffler
envp[1] 0x00007FFF62074F5A: PATH=/Users/jleffler/bin:/bin:/usr/bin
envp[2] 0x00007FFF62074F81: LANG=en_US.UTF-8
envp[3] 0x00007FFF62074F92: TERM=xterm-color
envp[4] 0x0000000000000000
$

これを注意深く調べれば、argv引数 tomain()がスタックのさらに上の文字列への一連のポインタの始まりであることがわかります。the envp(POSIX マシンではオプションの 3 番目の引数) は、グローバル変数and とmain()同じであり、スタックのさらに上の文字列への一連のポインターの開始点でもあります。およびポインタが指す文字列は、2 つの配列の後に続きます。environargv[argc+1]argvenvp

これは Mac OS X でのレイアウトです (10.7.5 は重要ですが、おそらく重要ではありません) が、他の Unix ライクなシステムでも同じレイアウトを見つけることができると確信しています。

于 2013-04-20T15:03:36.497 に答える