2012年11月28日 星期三

在 x86-64 上對 system call 使用 conditional break

在了解目標模組的動態行為時, 最近覺得從模組的 public interface 設中斷點是滿不錯的作法。廣意來說, system call 則是最一般化的 public interface, 從 system call 回頭夾擊目標也滿有效的。比方像這篇strace 找到切入點。

若想獲得更多資訊, 可以用 gdb 在 system call 上設中斷點, 一步步從退回來找到呼叫者、傳遞的資料等更多訊息。但在尋找 write、send 這類廣為使用的 system call 時, 被呼叫的次數過於頻繁, 就有點難找了。

查了一下, 看到這篇提到從 register 設定 conditional break 的方法:

(gdb) b write if 1==$rdi  # stop only when write(1, ...)

Scott 補充了以下的資訊:

要在 syscall argument 上設條件,且要 portable 以目前的工具不容易。用 gdb 的話需能背出『x86-64 上參數依序擺在 rdi, rsi, rdx, rcx, r8d, r9d』。 x86-64 上特別好記,因 syscall 與 一般 function call 被設計成將參數擺在同位置。ARM 上還有 64bit 參數開頭一定擺在偶數暫存器如 r0-r1, r2-r3 而不擺在 r1-r2 等規則。

目前 gdb 沒有將 syscall parameter 存在如 $syscall_arg0 的 convenience variable 中,否則寫: catch syscall write if $syscall_arg0 == 1 即可。

用 "system call calling convention" 當關鍵字查到《What are the calling conventions for UNIX & Linux system calls on x86-64》, 文中有許多相關資訊, 就先備忘吧。

1 則留言:

  1. 更正:
    x86-64 一般函式參數擺在 rdi, rsi, rdx, rcx, r8, r9
    Linux syscall 參數擺在 rdi, rsi, rdx, r10, r8, r9

    第四個參數放的位置不同: rcx VS. r10
    syscall 並可能複寫 rcx 與 r11

    見 http://www.x86-64.org/documentation/abi.pdf Appendix A, Linux Conventions

    傳統上 mmap() 是參數個數最多的 syscall (6 個)。x86-64 glibc mmap() syscall wrapper 如下:

    0x0000003c774eed40 <+0>: mov %rcx,%r10
    0x0000003c774eed43 <+3>: mov $0x9,%eax
    0x0000003c774eed48 <+8>: syscall
    0x0000003c774eed4a <+10>: cmp $0xfffffffffffff001,%rax
    0x0000003c774eed50 <+16>: jae 0x3c774eed53
    0x0000003c774eed52 <+18>: retq
    0x0000003c774eed53 <+19>: mov 0x2c20de(%rip),%rcx # 0x3c777b0e38
    0x0000003c774eed5a <+26>: neg %eax
    0x0000003c774eed5c <+28>: mov %eax,%fs:(%rcx)
    0x0000003c774eed5f <+31>: or $0xffffffffffffffff,%rax
    0x0000003c774eed63 <+35>: retq

    可見其中將 rcx 複製到 r10。放在 eax 中的常數 9 為 mmap 的 syscall number。retq 指令後是錯誤時執行的 code path,對應:

    if (-4095 <= eax && eax <= -1)
    errno = -eax; /* errno is thread local */
    return 0xffffffffffffffff;

    回覆刪除

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...