syscall
TODO:
- 【已解决】iOS去hook绕过syscall函数异常:可变参数计算个数再次异常12个13个
- 【已解决】iOS的tweak插件去hook函数syscall出现递归调用死循环
- 【已解决】iOS的tweak插件Logos的%orig的实现原理如何规避绕开原函数的递归调用
- 【未解决】iOS反越狱检测:syscall
syscall的fork
- 【已解决】iOS反越狱检测:syscall的fork
TODO:
syscall的stat和stat64
TODO:
- 【已解决】iOS反越狱检测hook绕过:syscall的stat和stat64
/*==============================================================================
Define
==============================================================================*/
#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif // !defined(PT_DENY_ATTACH)
/*==============================================================================
Const
==============================================================================*/
/*==============================================================================
Hook: syscall()
==============================================================================*/
/*
https://www.theiphonewiki.com/wiki/Kernel_Syscalls
TODO: support syscall(access_extended)
*/
int syscall(int, ...);
// normally max number of syscall parameter is not exceed 8
// refer: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/kern/syscalls.master
int MaxSupportArgNum_syscall = 16;
%hookf(int, syscall, int number, ...){
iosLogDebug("number=%d", number);
int syscallRetValue = -1;
// Setting up some variables to get all the parameters from syscall
void *paraPtr, *paraList[MaxSupportArgNum_syscall];
// char *paraPtr, *paraList[MaxSupportArgNum_syscall];
va_list argList;
int curParaNum = 0;
if (cfgHookEnable_syscall) {
// #define SYS_fork 2
bool isFork = (SYS_fork == number);
if (isFork){
iosLogInfo("number=%d -> return %d", number, FORK_FAILED);
return FORK_FAILED;
}
// #define SYS_open 5
bool isOpen = (SYS_open == number);
if (isOpen){
//int open(const char *path, int oflag, ...);
// ->
// int open(const char *pathname, int flags);
// int open(const char *pathname, int flags, mode_t mode);
//5 AUE_OPEN_RWTC ALL { int open(user_addr_t path, int flags, int mode) NO_SYSCALL_STUB; }
va_start(argList, number);
const char * fisrtPath = va_arg(argList, const char *);
int secondFlags = va_arg(argList, int);
// mode_t thirdMode = va_arg(argList, mode_t);
mode_t thirdMode = (mode_t)va_arg(argList, unsigned int);
va_end(argList);
iosLogDebug("fisrtPath=%{public}s, secondFlags=%d, thirdMode=%d", fisrtPath, secondFlags, thirdMode);
bool isJbPath = isJailbreakPath(fisrtPath);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
errno = ENOENT;
iosLogDebug("set errno=%d", errno);
syscallRetValue = OPEN_FAILED;
} else {
syscallRetValue = %orig(number, fisrtPath, secondFlags, thirdMode);
}
iosLogInfo("SYS_open: number=%d -> isJbPath=%{bool}d, fisrtPath=%{public}s -> syscallRetValue=%d", number, isJbPath, fisrtPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_ptrace 26
bool isPtrace = (SYS_ptrace == number);
if (isPtrace){
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/ptrace.2.html
// int ptrace(int request, pid_t pid, caddr_t addr, int data);
va_start(argList, number);
int request = va_arg(argList, int);
int pid = va_arg(argList, int);
char* addr = va_arg(argList, char*);
int data = va_arg(argList, int);
va_end(argList);
iosLogInfo("request=%d, pid=%d, addr=%p, data=%d", request, pid, addr, data);
if (PT_DENY_ATTACH == request){
syscallRetValue = PTRACE_FAILED;
} else {
syscallRetValue = %orig(request, pid, addr, data);
}
iosLogInfo("SYS_ptrace: request=%d, pid=%d, addr=%p, data=%d -> syscallRetValue=%d", request, pid, addr, data, syscallRetValue);
return syscallRetValue;
}
// #define SYS_access 33
bool isAccess = (SYS_access == number);
if (isAccess) {
// int access(const char *path, int amode);
va_start(argList, number);
const char* path = va_arg(argList, const char *);
int amode = va_arg(argList, int);
va_end(argList);
iosLogDebug("isAccess=%{bool}d, path=%{public}s, amode=0x%x", isAccess, path, amode);
bool isJbPath = isJailbreakPath(path);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = ACCESS_FAILED;
} else {
syscallRetValue = %orig(number, path, amode);
}
iosLogInfo("SYS_access: number=%d -> path=%{public}s, amode=0x%x -> isJbPath=%{bool}d -> syscallRetValue=%d", number, path, amode, isJbPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_statfs 157
bool isStatfs = (SYS_statfs == number);
if (isStatfs) {
// int statfs(const char *path, struct statfs *buf);
va_start(argList, number);
const char* path = va_arg(argList, const char *);
struct stat* buf = va_arg(argList, struct stat*);
va_end(argList);
iosLogDebug("isStatfs=%{bool}d, path=%{public}s, buf=%p", isStatfs, path, buf);
bool isJbPath = isJailbreakPath(path);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = STATFS_FAILED;
} else {
syscallRetValue = %orig(number, path, buf);
}
iosLogInfo("SYS_statfs: number=%d -> path=%{public}s, buf=%p -> isJbPath=%{bool}d -> syscallRetValue=%d", number, path, buf, isJbPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_fstatfs 158
bool isFstatfs = (SYS_fstatfs == number);
if (isFstatfs) {
bool isGetPathOk = false;
bool isJbPath = false;
char parsedPath[PATH_MAX];
memset(parsedPath, 0, PATH_MAX);
// int fstatfs(int fd, struct statfs *buf);
va_start(argList, number);
int fd = va_arg(argList, int);
struct stat* buf = va_arg(argList, struct stat*);
va_end(argList);
iosLogDebug("isFstatfs=%{bool}d, fd=%d, buf=%p", isFstatfs, fd, buf);
isGetPathOk = getFilePath(fd, parsedPath);
iosLogDebug("isGetPathOk=%s, parsedPath=%s", boolToStr(isGetPathOk), parsedPath);
if (isGetPathOk) {
isJbPath = isJailbreakPath(parsedPath);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = STATFS_FAILED;
} else {
syscallRetValue = %orig(number, fd, buf);
}
} else {
// can not get path -> can not check is jailbreak or not -> not hook
syscallRetValue = %orig(number, fd, buf);
}
iosLogInfo("SYS_fstatfs: number=%d -> fd=%d, buf=%p -> isJbPath=%{bool}d -> syscallRetValue=%d", number, fd, buf, isJbPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_stat 188
// #define SYS_stat64 338
bool isStat = (SYS_stat == number);
bool isStat64 = (SYS_stat64 == number);
if (isStat || isStat64){
//int stat(const char *, struct stat *) __DARWIN_INODE64(stat);
//int stat64(const char *, struct stat64 *) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_5, __MAC_10_6, __IPHONE_NA, __IPHONE_NA);
va_start(argList, number);
const char * fisrtPath = va_arg(argList, const char *);
void *secondStat = va_arg(argList, void *);
va_end(argList);
iosLogDebug("isStat=%{bool}d, isStat64=%{BOOL}d, fisrtPath=%{public}s, secondStat=%p", isStat, isStat64, fisrtPath, secondStat);
bool isJbPath = isJailbreakPath(fisrtPath);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = OPEN_FAILED;
} else {
// if (isStat){
// struct stat *statInfo = (struct stat *)secondStat;
// syscallRetValue = %orig(number, fisrtPath, statInfo);
// } else if(isStat64){
// struct stat64 *stat64Info = (struct stat64 *)secondStat;
// syscallRetValue = %orig(number, fisrtPath, stat64Info);
// }
syscallRetValue = %orig(number, fisrtPath, secondStat);
}
iosLogInfo("SYS_stat/SYS_stat64: number=%d -> isJbPath=%{bool}d, fisrtPath=%{public}s -> syscallRetValue=%d", number, isJbPath, fisrtPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_fstat 189
bool isFstat = (SYS_fstat == number);
if (isFstat) {
bool isGetPathOk = false;
bool isJbPath = false;
char parsedPath[PATH_MAX];
memset(parsedPath, 0, PATH_MAX);
// int fstat(int fd, struct stat *buf);
va_start(argList, number);
int fd = va_arg(argList, int);
struct stat* buf = (struct stat*)va_arg(argList, void *);
va_end(argList);
iosLogDebug("isFstat=%{bool}d, fd=%d, buf=%p", isFstat, fd, buf);
isGetPathOk = getFilePath(fd, parsedPath);
iosLogDebug("isGetPathOk=%{bool}d, parsedPath=%s", isGetPathOk, parsedPath);
if (isGetPathOk) {
isJbPath = isJailbreakPath(parsedPath);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = STAT_FAILED;
} else {
syscallRetValue = %orig(number, fd, buf);
}
} else {
syscallRetValue = %orig(number, fd, buf);
}
iosLogInfo("SYS_fstat: number=%d -> fd=%d -> isGetPathOk=%{bool}d, parsedPath=%{public}s -> isJbPath=%{bool}d -> syscallRetValue=%d", number, fd, isGetPathOk, parsedPath, isJbPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_lstat 190
bool isLstat = (SYS_lstat == number);
if (isLstat) {
// int lstat(const char* path, struct stat* buf);
va_start(argList, number);
const char* fisrtPath = va_arg(argList, const char *);
struct stat* secondBuf = (struct stat*)va_arg(argList, void *);
va_end(argList);
iosLogDebug("isLstat=%{bool}d, fisrtPath=%{public}s, secondBuf=%p", isLstat, fisrtPath, secondBuf);
bool isJbPath = isJailbreakPath(fisrtPath);
iosLogDebug("isJbPath=%{bool}d", isJbPath);
if (isJbPath){
syscallRetValue = STAT_FAILED;
} else {
syscallRetValue = %orig(number, fisrtPath, secondBuf);
}
iosLogInfo("SYS_lstat: number=%d -> isJbPath=%{bool}d, fisrtPath=%{public}s -> syscallRetValue=%d", number, isJbPath, fisrtPath, syscallRetValue);
return syscallRetValue;
}
// #define SYS_fstatat 469
bool isFstatat = (SYS_fstatat == number);
if (isFstatat) {
bool isJbPath = false;
// int fstatat(int dirfd, const char *pathname, struct stat *buf, int flags);
va_start(argList, number);
int dirfd = va_arg(argList, int);
const char *pathname = (const char *)va_arg(argList, void *);
struct stat *buf = (struct stat*)va_arg(argList, void *);
int flags = va_arg(argList, int);
va_end(argList);
iosLogDebug("isFstatat=%{bool}d, dirfd=%d, pathname=%{public}s, buf=%p, flags=%d", isFstatat, dirfd, pathname, buf, flags);
const char* absPath = NULL;
bool isAbsPath = strStartsWith(pathname, "/");
iosLogDebug("isAbsPath=%{bool}d", isAbsPath);
if (isAbsPath) {
absPath = pathname;
} else {
// is relative path
if (dirfd == AT_FDCWD){
iosLogDebug("dirfd is AT_FDCWD=%d", AT_FDCWD);
// pathname is interpreted relative to the current working directory of the calling process (like access())
// TODO: try get current working directory -> avoid caller pass the special path, finnaly is jailbreak path
// eg: current working directory is "/usr/xxx/yyy/", then pass in "../../libexec/cydia/zzz"
// finnal path is "/usr/libexec/cydia/zzz", match jailbreak path: "/usr/libexec/cydia/", is jaibreak path
// but use "../../libexec/cydia/zzz" can not check whether is jailbreak path
} else {
// get file path from dir fd
char filePath[PATH_MAX];
bool isGetPathOk = getFilePath(dirfd, filePath);
iosLogDebug("isGetPathOk=%s", boolToStr(isGetPathOk));
if (isGetPathOk) {
char* fullPath = strPathJoin(filePath, pathname)
iosLogDebug("fullPath=%{public}s", fullPath);
absPath = fullPath;
}
}
}
if (NULL != absPath){
isJbPath = isJailbreakPath(absPath);
iosLogDebug("absPath=%{public}s -> isJbPath=%{bool}d", absPath, isJbPath);
if (isJbPath) {
iosLogDebug("hook jailbreak path: %s", absPath);
syscallRetValue = STATFS_FAILED;
} else {
syscallRetValue = %orig(number, dirfd, pathname, buf, flags);
}
} else {
syscallRetValue = %orig(number, dirfd, pathname, buf, flags);
}
iosLogInfo("SYS_fstatat: number=%d -> dirfd=%d, pathname=%{public}s, buf=%p, flags=0x%x -> isJbPath=%{bool}d -> syscallRetValue=%d", number, dirfd, pathname, buf, flags, isJbPath, syscallRetValue);
return syscallRetValue;
}
}
va_start(argList, number);
while ((paraPtr = (void *) va_arg(argList, void *))) {
// while ((paraPtr = (char *) va_arg(argList, char *))) {
paraList[curParaNum] = paraPtr;
curParaNum += 1;
iosLogDebug("[%d] paraPtr=%p", curParaNum, paraPtr);
}
va_end(argList);
// iosLogDebug("argList=%{public}s", argList);
iosLogDebug("curParaNum=%d", curParaNum);
// return %orig;
// return %orig(number, ...);
// int retValue = %orig();
// int retValue = callOriginSyscall(number, curParaNum, paraList);
//// int retValue = callOriginSyscall(number, curParaNum, (void *)paraList);
// iosLogDebug("retValue=%d", retValue);
// return retValue;
int paraNum = curParaNum;
if (0 == paraNum){
syscallRetValue = %orig(number);
} else if (1 == paraNum){
void* para1 = paraList[0];
iosLogDebug("para1=%p", para1);
syscallRetValue = %orig(number, para1);
} else if (2 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
iosLogDebug("para1=%p,para2=%p", para1, para2);
syscallRetValue = %orig(number, para1, para2);
} else if (3 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
iosLogDebug("para1=%p,para2=%p,para3=%p", para1, para2, para3);
syscallRetValue = %orig(number, para1, para2, para3);
} else if (4 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p", para1, para2, para3, para4);
syscallRetValue = %orig(number, para1, para2, para3, para4);
} else if (5 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p,para5=%p", para1, para2, para3, para4, para5);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5);
} else if (6 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p", para1, para2, para3, para4, para5, para6);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6);
} else if (7 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p", para1, para2, para3, para4, para5, para6, para7);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7);
} else if (8 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p", para1, para2, para3, para4, para5, para6, para7, para8);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8);
} else if (9 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
void* para9 = paraList[8];
iosLogDebug("para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p,para9=%p", para1, para2, para3, para4, para5, para6, para7, para8, para9);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8, para9);
}
iosLogInfo("number=%d -> syscallRetValue=%d", number, syscallRetValue);
return syscallRetValue;
}