ar_u_ok
主要考察對ptrace的認識和rc6,rc4的識別
加密解密
真正的加密和解密過程很簡單,就是一個標準的rc6,只要把函數中的那個int常量放到google里搜索一下就知道是rc6加密(這個函數的代碼被rc4加密了,不不解密是看不到的)。
rc6加密和解密的代碼見源碼
程序流程
程序首先判斷啟動參數,如果argc為1,則以debugger身份啟動,利用fork分出parent和child。parent作為真正的debugger,child利用execve來啟動自身并以父進程的pid作為啟動參數。
如果argc為2,說明是debuggee。程序利用puts打印plz_input_flag,但是write的syscall被ptrace hook了。puts的原始內容是亂碼,需要debugger對其進行解密。
然后是利用scanf來接收flag。默認是允許輸入%48s但是這里ptrace hook了read syscall,檢測read syscall觸發的次數(在程序開頭利用setbuf將stdin和stdout的緩沖調整為0),從而使flag的真實最大長度為32。
接著是一段判斷是否調試者為父進程的代碼,沒問題的話會調用fclose來關閉之前打開的文件。此處用ptrace hook了close syscall。但是在程序運行前也會調用close syscall。這里利用設置變量的方式,使得在第二次close的時候觸發。
觸發時執行的代碼是利用rc4將兩個函數解密,然后patch代碼為0xcc使程序停在檢測trace代碼的下一行,在將其patch成jmp到data段的那段唯一可視的雷軍ascii字符處,并將flag傳遞給rdx,接著繼續執行。雷軍那段ascii其實是代碼。前面的52Mi!是xor eax, 0x21694d32,從而使后面的jne全部成立,R_是push rdx;pop rdi,從而將之前在rdx中的flag傳遞到rdi中。利用u_這個jne跳轉跳過中間的非代碼區,最后jmp到encrypt函數中。
encrypt函數就是調用rc6加密,將32位的flag分16位兩次加密,最后和enc結果比較。
由于調用了很多的ptrace來實現smc和hook,純動態分析應該不太可能實現,需要靜態分析后patch程序才能使用動態分析。
完整程序見github,由于有smc部分,可能在不同機子上編譯結果不正確,所以提供了一個測試用的binary。
2017HCTF-Writeup