gdb でレジスタの値を書き換えてみる

同僚に教えてもらった gdb で実行中のプロセスにアタッチして、writeシステムコール発行直前でレジスタのファイルディスクリプタを書換えるというのを試してみた。

  • write_loop.c
#include <unistd.h>

int main(void)
{
        while(1) {
                write(1, "foo\n", 4);
        }
}
$ gcc -o write_loop write_loop.c
  • 実行する
$ ./write_loop > foo.log
  • PID を調べて、
$ ps auxw|grep [w]rite_loop
yazekats  5873 97.6  0.0   3968   284 pts/0    R+   22:01   1:18 ./write_loop
$ ls -l /proc/5873/fd 
total 0
lrwx------ 1 yazekats yazekats 64 Dec 19 22:10 0 -> /dev/pts/0
l-wx------ 1 yazekats yazekats 64 Dec 19 22:10 1 -> /home/yazekats/Documents/work/foo.log
lrwx------ 1 yazekats yazekats 64 Dec 19 22:03 2 -> /dev/pts/0
  • gdb でプロセスにアタッチする
$ gdb -p 5873
(gdb) b write
Breakpoint 1 at 0x3ba66db780
(gdb) n
Single stepping until exit from function write,
which has no line number information.
0x00000000004004dc in main ()
(gdb) n
Single stepping until exit from function main,
which has no line number information.

Breakpoint 1, 0x0000003ba66db780 in write () from /lib64/libc.so.6
(gdb) info reg
rax            0x4	4
rbx            0x0	0
rcx            0xffffffffffffffff	-1
rdx            0x4	4
rsi            0x4005d8	4195800
rdi            0x1	1 ★FDは1の標準出力
rbp            0x7fff77c9b5a0	0x7fff77c9b5a0
rsp            0x7fff77c9b598	0x7fff77c9b598
r8             0x3ba698f300	256198112000
r9             0x3ba620e9f0	256190245360
r10            0x7fff77c9b320	140735203095328
r11            0x246	582
r12            0x4003e0	4195296
r13            0x7fff77c9b680	140735203096192
r14            0x0	0
r15            0x0	0
rip            0x3ba66db790	0x3ba66db790 <__write_nocancel+7>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) set $rdi=2
(gdb) info reg
rax            0x4	4
rbx            0x0	0
rcx            0xffffffffffffffff	-1
rdx            0x4	4
rsi            0x4005d8	4195800
rdi            0x2	2 ★FDが2の標準エラーに変わっている
rbp            0x7fff77c9b5a0	0x7fff77c9b5a0
rsp            0x7fff77c9b598	0x7fff77c9b598
r8             0x3ba698f300	256198112000
r9             0x3ba620e9f0	256190245360
r10            0x7fff77c9b320	140735203095328
r11            0x246	582
r12            0x4003e0	4195296
r13            0x7fff77c9b680	140735203096192
r14            0x0	0
r15            0x0	0
rip            0x3ba66db790	0x3ba66db790 <__write_nocancel+7>
eflags         0x246	[ PF ZF IF ]
cs             0x33	51
ss             0x2b	43
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) n

お、標準エラーに出力された!

$ ./write_loop > foo.log
foo ← これが出力される