目次: C言語とlibc
Linuxはプロセスの起動時に、引数や環境変数に加えてAuxiliary Vector(補助ベクタ−)というデータを渡します。ダンプするにはLD_SHOW_AUXVを定義してから起動すると良いです。
$ LD_SHOW_AUXV=1 /bin/echo AT_SYSINFO_EHDR: 0x7ffec8bcc000 AT_??? (0x33): 0x6f0 AT_HWCAP: 178bfbff AT_PAGESZ: 4096 AT_CLKTCK: 100 AT_PHDR: 0x5650e2ab4040 AT_PHENT: 56 AT_PHNUM: 11 AT_BASE: 0x7f5d30b65000 AT_FLAGS: 0x0 AT_ENTRY: 0x5650e2ab6980 AT_UID: 1000 AT_EUID: 1000 AT_GID: 1000 AT_EGID: 1000 AT_SECURE: 0 AT_RANDOM: 0x7ffec8bb3499 AT_HWCAP2: 0x2 AT_EXECFN: /bin/echo AT_PLATFORM: x86_64
補助ベクターは基本的には存在するかしないか定かではなく任意です。が、どうもglibcはいくつかの補助ベクターの存在を前提としていて、存在しない場合は起動すらしないようです。
補助ベクターを変更するスマートな方法がありそうですが、わかりませんでした。仕方ないのでデバッガを使って力尽くで書き換えます。まずはテストプログラムを書きます。mainに到達する前のことを扱うためプログラムの中身は何でも良いです。
// a.c
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
printf("hello\n");
return 0;
}
実行してmainでブレークし、環境変数の配列envpをダンプします。envpの終端はNULLポインタですが、実はその先に補助ベクターが置かれています。
$ gcc -Wall -g -O0 -static a.c $ gdb a.out ... (gdb) b main Breakpoint 1 at 0x4017d8: file a.c, line 5. (gdb) r Starting program: /home/katsuhiro/share/a/a.out Breakpoint 1, main (argc=1, argv=0x7fffffffdcf8, env=0x7fffffffdd08) at a.c:5 5 printf("hello\n"); (gdb) x/32x envp 0x7fffffffdd08: 0xffffe039 0x00007fff 0xffffe049 0x00007fff 0x7fffffffdd18: 0xffffe05c 0x00007fff 0xffffe070 0x00007fff 0x7fffffffdd28: 0xffffe089 0x00007fff 0xffffe09f 0x00007fff 0x7fffffffdd38: 0xffffe0b3 0x00007fff 0xffffe495 0x00007fff 0x7fffffffdd48: 0xffffe4a9 0x00007fff 0xffffe4d8 0x00007fff 0x7fffffffdd58: 0xffffe503 0x00007fff 0xffffe50c 0x00007fff 0x7fffffffdd68: 0xffffe534 0x00007fff 0xffffe549 0x00007fff 0x7fffffffdd78: 0xffffe55e 0x00007fff 0xffffe571 0x00007fff (...略...) 0x7fffffffde88: 0xffffefb1 0x00007fff 0x00000000 0x00000000 ★★envpの終端★★ 0x7fffffffde98: 0x00000021 0x00000000 0xf7ffd000 0x00007fff ★★補助ベクターの始まり★★ ...
補助ベクターは下記のような構造です。
typedef struct
{
long int a_type; /* Entry type */
union
{
long int a_val; /* Integer value */
void *a_ptr; /* Pointer value */
void (*a_fcn) (void); /* Function pointer value */
} a_un;
} auxv_t;
簡単に言えばx86_64の場合8バイトのtypeと、8バイトのunionが並んでいるだけです。最初のデータ(アドレス0x7fffffffde98)を例に取るとtype = 0x21, data = 0x7fff_f7ff_d000です。わかりやすいですね。
デバッガから起動する場合はargv, envp, 補助ベクターのアドレスは常に同じです。そのため、
このような手順を取ってglibcが補助ベクターを見る前に補助ベクターの値を好きに変更できます。試しにglibcが起動時に参照していてNULLにすることが許されないAT_RANDOMを書き換えます。AT_RANDOMはtype = 0x19です。
(gdb) b _start Breakpoint 2 at 0x4016a0 (gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/katsuhiro/share/a/a.out Breakpoint 2, 0x00000000004016a0 in _start () (gdb) x/32x 0x7fffffffde98 0x7fffffffde98: 0x00000021 0x00000000 0xf7ffd000 0x00007fff 0x7fffffffdea8: 0x00000033 0x00000000 0x000006f0 0x00000000 (...略...) 0x7fffffffdf98: 0x00000019 0x00000000 0xffffdfe9 0x00007fff ★★書き換え対象AT_RANDOM★★ 0x7fffffffdfa8: 0x0000001a 0x00000000 0x00000002 0x00000000 0x7fffffffdfb8: 0x0000001f 0x00000000 0xffffefce 0x00007fff 0x7fffffffdfc8: 0x0000000f 0x00000000 0xffffdff9 0x00007fff 0x7fffffffdfd8: 0x00000000 0x00000000 0x00000000 0x00000000 ★★補助ベクターの終端type = 0★★ 0x7fffffffdfe8: 0xf8e1f900 0x056adb4e 0xb6df71ae 0x67d4fca2 ... (gdb) set *0x7fffffffdfa0=0 (gdb) set *0x7fffffffdfa4=0 (gdb) x/32x 0x7fffffffdf98 0x7fffffffdf98: 0x00000019 0x00000000 0x00000000 0x00000000 ★★NULLポインタに書き換えた★★ 0x7fffffffdfa8: 0x0000001a 0x00000000 0x00000002 0x00000000 0x7fffffffdfb8: 0x0000001f 0x00000000 0xffffefce 0x00007fff ... (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x00000000004032fd in __libc_start_main ()
実行を継続するとmainに到達することなくSEGVでクラッシュします。glibcは起動時にAT_RANDOMの指す配列を参照していて、アドレスをNULLポインタに書き換えたからです。glibcはLinux専用のlibcですから、AT_RANDOMが存在しない場合を考慮する必要はないとはいえ、なんか微妙な動作ですね……うーん。
< | 2022 | > | ||||
<< | < | 04 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
合計:
本日:
管理者: Katsuhiro Suzuki(katsuhiro( a t )katsuster.net)
This is Simple Diary 1.0
Copyright(C) Katsuhiro Suzuki 2006-2023.
Powered by PHP 8.2.15.
using GD bundled (2.1.0 compatible)(png support.)