動機

接著說說strace與ltrace

strace & ltrace

用法: strace -e {syscall_want_to_trace,...} {cmd & its args} ltrace -e {syscall_want_to_trace,...} {cmd & its args}

strace會列出syscall,ltrace是列出lib 的 function call 兩個都是透過ptrace來完成 strace與ltrace是透過ptrace讓發生事件時讓process停下來

ptrace

ptrace是linux的process debug框架,在thread發生下面的case發生時回報給追蹤者(process)

  • 收到signal (除了SIGKILL)
    • 可以攔截singal,進而轉發、送新signal
  • 跑syscall
  • 跑到被ptrace參數指定的事件
  • 被停下來時

ptrace的流程是

  • 登記 (PTRACE_ATTACH, PTRACE_SEIZE, PTRACE_TRACEME(對象是child))
  • 設參數
  • waitpid
  • 取得在意的資料
  • PTRACE_CONT

strace需要PTRACE_ATTACH、PTRACE_SYSCALL,所以下面就看這兩項

PTRACE_ATTACH

一開始先登記

  1. 先到泛用的ptrace syscall
  2. 之後開始檢查被trace的程式能不能用ptrace,之後替該process上被attach的flag
  3. 之後根據流程,ptrace會跑到arch-specific的ptrace code
    • 但沒有PTRACE_ATTACH事就直接退出
  4. 這個時候被trace的程式會停下來

PTRACE_SEIZE

PTRACE_ATTACH很像,但是PTRACE_SEIZE不會讓process停下來,PTRACE_ATTACH會先讓process停下來

所以做PTRACE_SEIZE的同時可以加上ptrace的參數,PTRACE_ATTACH因為會先stop,所以要等到對方停了才可以另外加ptrace的參數

PTRACE_SYSCALL

登記好了就讓他跑吧

  1. 先到泛用的ptrace syscall
  2. 之後開始檢查被trace的程式能不能用ptrace,之後替該process上被attach的flag
  3. 之後根據流程,ptrace會跑到arch-specific的ptrace code
    • 會call ptrace_resume,之後再thread上打TIF_SYSCALL_TRACE的flag
  4. 被trace的程式就開始跑

call system call了

  1. 在執行system call的程式中會看有沒有TIF_SYSCALL_TRACE或是其他在此無關的flag,有就會call tracesys
  2. tracesys中會看有沒有TIF_SYSCALL_TRACE,有就call ptrace_report_syscall
  3. ptrace_report_syscall
    • SIGTRAP kill 被trace的程式,讓他停下來
    • 執行trace的程式會被通知,就可以看需要的東西了

ltrace & interrupt 3

如果不想看syscall只想看function call怎麼辦?

interrupt 3 (software breakpoint)

執行後,kernel會用SIGTRAP kill執行interrupt 3的process

所以這樣ptrace看的到,但要怎麼插入interrupt 3?

PTRACE_POKETEXT & the Procedure Linkage Table (PLT) and the Global Offset Table (GOT)

PTRACE_POKETEXT可以讓ptrace插入code,可以用他插入interrupt 3

process(ELF)有

  • Global Offset Table (GOT): shared lib的位置
  • Procedure Linkage Table (PLT): 紀錄怎麼call function的code
    • 如果是shared lib就是變成調用linker
    • linker找到後會把位置填到GOT,跑function
    • 之後的同一個function call就是找GOT上寫的位置直接call function

ltrace = irq 3 + PTRACE_POKETEXT

  • 先登記 (attach)
  • 查PLT,用PTRACE_POKETEXT插入interrupt 3
  • 讓被trace的程式開始跑
  • 之後就是SIGTRAP
  • 等結束後,再用PTRACE_POKETEXT把原本的code插回去

Ref

How does strace work? How does ltrace work? Understanding ptrace ptrace man