防護
當一個程式被除錯時,該程式會有一個標誌位來標記他正在被標記。sysctl
函式可用於檢視當前程式的資訊。
-
使用該函式,需要匯入系統庫
#import <sys/sysctl.h>
。 -
函式介紹
/* 函式的返回值若為0時,證明沒有錯誤,其他數字為錯誤碼。 arg1 傳入一個陣列,該陣列中的第一個元素指定本請求定向到核心的哪個子系統。第二個及其後元素依次細化指定該系統的某個部分。 arg2 陣列中的元素數目 arg3 一個結構體,指向一個供核心存放該值的緩衝區,存放程式查詢結果 arg4 緩衝區的大小 arg5/arg6 為了設定某個新值,arg5引數指向一個大小為arg6引數值的緩衝區。如果不準備指定一個新值,那麼arg5應為一個空指標,arg6因為0. */ int sysctl(int *, u_int, void *, size_t *, void *, size_t); 複製程式碼
-
函式使用
int name[4];//存放位元組碼,查詢資訊 name[0] = CTL_KERN;//核心檢視 name[1] = KERN_PROC;//程式檢視 name[2] = KERN_PROC_PID//程式ID name[3] = getpid();//獲取pid,據說這個可以直接傳0??? struct kinfo_proc info;//接受程式查詢結果資訊的結構體 size_t info_size = sizeof(info);//結構體的大小 int proc_err = sysctrl(name, sizeof(name)/sizeof(*name), info, info_size, 0, 0); assert(proc_err == 0);//出現異常,出發斷言 //info.kp_proc.p_flag中存放的是標誌位(二進位制),在proc.h檔案中有p_flag的巨集定義,通過&運算可知對應標誌位的值是否為0。(若結果值為0則對應標誌位為0)。其中P_TRACED為正在跟蹤除錯過程。 ((info.kp_proc.p_flag & P_TRACED) != 0)的結果即為是否處於除錯狀態。 複製程式碼
進攻
可以通過fishhook交換掉系統的sysctl函式,原始碼很少,網上分析很多。關於fishhook的更多東西,具體請百度,這裡直接使用。
程式碼如下:
//函式指標,儲存原方法。
int (*sysctl_p)(int *, u_int, void *, size_t *, void *, size_t);
//用來交換的新方法
int mySysctl(int *name, u_int namelen, void *info, size_t *infosize, void *newinfo, size_t newinfosize){
int err = sysctl_p(name, namelen, info, infosize, newinfo, newinfosize);
//判斷是否是查詢程式資訊
if (namelen == 4
&&name[0] == CTL_KERN
&&name[1] == KERN_PROC
&&name[2] == KERN_PROC_PID
&&info
&&((int)*infosize == sizeof(struct kinfo_proc))) {
//接受結果的結構體
struct kinfo_proc* sys_info = (struct kinfo_proc *)info;
//通過標誌位確認是否為除錯狀態
if ((sys_info->kp_proc.p_flag & P_TRACED) != 0) {
//進行異或運算修改標誌位
sys_info->kp_proc.p_flag ^= P_TRACED;
}
}
return err;
}
複製程式碼
然後在+(void)load;
方法中交換系統的sysctl
方法
rebind_symbols((struct rebinding[1]){{"sysctl",mySysctl,(void *)&sysctl_p}}, 1);
複製程式碼
防護
對於fishhook交換系統函式的進攻方式,我們可以通過將sysctl函式呼叫放到動態庫中,以保證檢測函式可以在進攻注入的程式碼之前執行。動態庫的載入順序為Build Phases
下的Link Binary With Libaraies
中的排列順序。