Skip to content

Instantly share code, notes, and snippets.

@shiv3 shiv3/advent3.md
Last active Nov 1, 2019

Embed
What would you like to do?
プロセスアタッチ系の話

##プロセスアタッチ系の話


この記事は OIC ITCreate Club Advent Calendar 2015 11日目(12/11)の記事です。

誰も書かなそうだったので放置してたやつをせっかくなので11日目ということで。

人が動かしてるシェルとかプログラムとかにイタズラしたい、とか

バックグラウンドで動かしちゃってるプログラムの入出力を見たい、とか

そういうとき便利そうなやつをまとめてみましt

  • ptrace

    ptrace()システムコールで頑張る方法。

    • 別のプロセスの監視、制御(メモリやレジスタを見たり、書き込んだり)が出来る。
    • デバッガを実装するときに使う。
    • 使えるとわりと便利。

    軽い説明

     #include <sys/ptrace.h>
     
    

    sys/ptrace.hをインクルード

     long ptrace(enum __ptrace_request request, pid_t pid,
             void *addr, void *data);
    

    requestのところにptraceに実行させる命令を入れて使用する。

    よく使いそうな例

    • PTRACE_TRACEME

      このプロセスを親プロセスにトレースさせる。

       	ptrace(PTRACE_TRACEME, 0, 0, 0);
       	//request以外の引数は無視
      
      

      使い方として、親プロセスでfork(2)して、生成された子プロセスでPTRACE_TRACEMEをし、exec(3)をしていく。(らしい このプロセスがexecve(2)を呼び出す度にSIGTRAPが親に行く。

      今回は使わない。省略。

    • PTRACE_ATTACH

      指定したpidにアタッチする。 アタッチしたプロセスは子プロセスとしてトレース出来る。

      一番使いそうな感じ

       ptrace(PTRACE_ATTACH, pid, 0, 0);
      
       //or
      
       ptrace(PTRACE_ATTACH, pid, NULL, NULL);
      
       //or
      
       ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_flags);
      
      

    • 需要なさそうな説明

      PTRACE_ATTACH命令はプロセスにSIGSTOPシグナルを送って、プログラムを一時停止させる。子プロセスはPTRACE_TRACEMEをしたかのように振る舞う。呼び出し元プロセスは子プロセスの実際の親として表示される。でもgetppid(2)したときには元の親プロセスのPIDが返される。

      停止を待つ場合はwait(2)を使用する。


    • PTRACE_DETACH

      停止した子プロセスを再開する。

      そのプロセスからの分離を行い、PTRACE_ATTACHでの親の切り換えによる効果とPTRACE_TRACEMEの効果を取り消す。(PTRACE_CONTを使う場合は分離のみ)

      Linuxだとトレースされている子プロセスはこれでdetach出来る。

    • PTRACE_PEEKTEXT

      メモリのaddrの位置を参照

    • PTRACE_POKETEXT

      dataをメモリのaddrの位置に書き込む。

    ここがとても参考になった

    他面白そうなのはこちらを見て下さい。


  • python-ptrace

    pythonのptraceライブラリのバインディング

    便利そう(使ってない

  • strace

    システムコールをトレース出来る。

    ptraceで使って作ってる。

    使い方は

     strace -p PID
    

    とかで別プロセスにアタッチして使う。

    簡単な使い方

    testユーザーが実行しているbashの標準入出力とか見る。

    • testユーザーの実行しているbashのpidを調べる

       root@test:~# ps au  | grep test.*bash
      

    test 15655 0.1 0.4 22012 5052 pts/3 S+ 10:47 0:00 -bash root 15683 0.0 0.1 11464 1772 pts/0 S+ 10:47 0:00 grep test.*bash

      ```
      pidは15655
    
    • straceでアタッチ

       root@test:~# strace -p 15655 -e read
       Process 15655 attached
       read(0,
      
      

      こうやっておくと

       test@test:~$ ls
      
      

      testユーザーが入力している文字が分かる

       read(0, "l", 1)                         = 1
       read(0, "s", 1)                         = 1
       read(0, "\r", 1)                        = 1
      
      

      writeにしておくと出力が取れる。

       root@test:~# strace -p 15760 -e write
       Process 15760 attached
      
      
       test@test:~$ pwd
       /home/test
      
      
       root@test:~# strace -p 15760 -e write
       Process 15760 attached
       write(2, "p", 1)                        = 1
       write(2, "w", 1)                        = 1
       write(2, "d", 1)                        = 1
       write(2, "\n", 1)                       = 1
       write(1, "/home/test\n", 11)            = 11
      
      

      keyloggerにならなくもない

    straceでプログラムを開始するのはstrace ./a.outみたいな感じで

    ltrace使うとプロセスがどういう共有ライブラリの関数を呼び出しているか見れる。

     	test@test:~$ cat test2.c   
     	#include <unistd.h>
     	#include <stdio.h>
    
     	int main() {
     	printf("test");
     	sleep(1);
     	printf("test");
     	return 0;
    
     	}
     	test@test:~$ gcc test2.c -o test2
     	test@test:~$ ltrace ./test2  
     	__libc_start_main(0x400546, 1, 0x7ffc46dd7aa8, 0x400580 <unfinished ...>
     	printf("test")                                   = 4
     	sleep(1)                                         = 0
     	printf("test")                                   = 4
     	testtest+++ exited (status 0) +++
    
    
  • gdb

    すごいやつ

    とてもすごいので書ききれないので詳しい使い方は省略。

    今回はプロセスにアタッチする方法を

    -p でアタッチしたいプロセスを指定する

     root@test:~# ps au | grep test      
     test     15760  0.0  0.5  22088  5256 pts/2    S+   	12:22   0:00 -bash
    
     root@test:~# gdb -p 15760
     
    

    今回はtestユーザのbashを指定。

    testユーザーは何も操作ができなくなる。

    sshでやる場合、長時間アタッチすると接続がタイムアウトするので注意。

    printでシステムコールが使える。

     (gdb) print system("echo omae ha mou nottorarete iru")
    

$1 = 0

```

```
test@test:~$ omae ha mou nottorarete iru
```

他人のアカウントでコマンドが実行できる。(^u^)

アタッチを解除する場合はdetach

```
(gdb) detach
```
  • lsof

    プロセスがオープンしてるファイルとか見れる 強い

     root@test:~# lsof -p 15760
    

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 15760 test cwd DIR 254,3 4096 820272 /home/test bash 15760 test rtd DIR 254,3 4096 2 /

```
  • screenify

    gdbの方法が面倒な場合、完全にプロセスを乗っ取りたい場合に使える。gdbを使ったスクリプト。

    ダウンロードしてきて実行する

      chmod +x screenify 
      ./screenify 16804
      64 bytes from 8.8.8.8: icmp_seq=3 ttl=52 time=18.2 ms
      64 bytes from 8.8.8.8: icmp_seq=4 ttl=52 time=18.3 ms
      64 bytes from 8.8.8.8: icmp_seq=5 ttl=52 time=18.5 ms
      64 bytes from 8.8.8.8: icmp_seq=6 ttl=52 time=18.4 ms
     
    

    screenify

  • reptyr

    同じようなやつだけどscreenifyで不便なとこをわりとなんとかしてくれてる。

    reptyr

    詳しくは

    http://mojavy.com/blog/2013/07/12/reptyr/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.