macOS Hook系統(tǒng)調用

前面曾簡單介紹過基于Kauth或者EndpointSecurity框架可以監(jiān)視系統(tǒng)的各類文件、進程事件,在審計后阻斷或放通事件的執(zhí)行。其中基于內核拓展的方案除了可以阻斷執(zhí)行,還可以修改函數調用參數,進行諸如文件保護、網絡隔離等操作。

編寫內核拓展較為復雜且可能導致系統(tǒng)崩潰等嚴重后果。Apple提供了在用戶態(tài)hook函數調用的機制,使用較為方便,稱為動態(tài)庫注入。動態(tài)庫注入是dyld加載器提供的功能,通過修改環(huán)境變量DYLD_INSERT_LIBRARIES可向二進制注入動態(tài)庫。注入的動態(tài)庫需實現函數替換,Apple提供了dyld-interposing方法,使用如下。

#ifndef DYLD_INTERPOSE
    #define DYLD_INTERPOSE(_replacement,_replacee) \
        __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee \
        __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
#endif

該段宏定義的目的是修改MachO文件的DATA區(qū)的interpose字段,目的是將原始函數的地址替換為自定義函數地址,dyld在加載動態(tài)庫時對該地址進行替換。如這里對進程執(zhí)行的系統(tǒng)調用execve和posix_spawn進行替換,將映像更換為echo,讀者可自行查看是否完成替換。注意,調用printf函數不一定可以打印出來,具體原因不太明白,猜測是因為printf屬于懶加載函數,注入動態(tài)庫時該函數地址沒有更新,無法調用。

static const char *s_repalce_path = "/bin/echo";

int fh_execve(const char *file, char *const *argv, char *const *envp) {
    printf("[FishHook - execve] pid: %d, process path: %s.", getpid(), file);
    return execve(s_repalce_path, argv, envp);
}

int fh_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *actions, const posix_spawnattr_t *attr, char *const *argv, char *const *envp) {
    printf("[FishHook - posix_spawn] pid: %d, process path: %s.", *pid, path);
    return posix_spawn(pid, s_repalce_path, actions, attr, argv, envp);
}

DYLD_INTERPOSE(fh_execve, execve)
DYLD_INTERPOSE(fh_posix_spawn, posix_spawn)

需要注意的是,在開啟SIP (System Integrity Protection) 機制的機器上,簽名的應用程序可能無法繼承該環(huán)境變量,原因是內核會進行防止可執(zhí)行文件被修改的檢查,可參考Apple官方的SIP指南。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容